乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      微服務(wù)實戰(zhàn)之 Cassandra

       jackeyqing 2019-12-07

      概述

      一提到數(shù)據(jù)存儲馬上我們就會想到數(shù)據(jù)庫, 一想數(shù)據(jù)庫就會想到 Oracle, MySQL等關(guān)系數(shù)據(jù)庫。

      其實今天擺在我們面前有更多選擇, 例如

      • 迷你版的關(guān)系數(shù)據(jù)庫 SQLite
      • 流行的開源數(shù)據(jù)庫 MySQL
      • 強(qiáng)大的開源數(shù)據(jù)庫 PGSQL
      • 時間序列數(shù)據(jù)庫 InfluxDB

      和眾多的 NoSQL 數(shù)據(jù)存儲系統(tǒng)

      • Cassandra
      • Riak
      • Redis
      • MongoDB

      以及分布式文件存儲系統(tǒng)

      • HDFS
      • Swift (Openstack Object Storage)

      Cassandra 是 NoSQL 的典型代表產(chǎn)品, 具有極佳的線性可擴(kuò)展性和高可用性, 同時性能也不錯, 跨Data center的復(fù)制也還行, 不足之處在于它做不到強(qiáng)一致性, 不要指望寫入Cassandra的數(shù)據(jù), 別人立馬就能正確無誤地由讀出來. 與大多數(shù)NOSQL產(chǎn)品一樣, 它所能保證的只能是最終一致性.

      先復(fù)習(xí)一下相關(guān)理論

      CAP

      著名的CAP理論提出一致性,可用性,分區(qū)容錯性,三者不可兼得

      C:Consistency,一致性, 在不同的地方和時間點(diǎn)上數(shù)據(jù)總是一致的
      A:Availability,可用性, 在任何地點(diǎn)和時間都可以使用服務(wù)
      P:Partition tolerance,分區(qū)容錯性,即使出現(xiàn)網(wǎng)絡(luò)故障系統(tǒng)依然具有可靠

      大多數(shù) nosql 產(chǎn)品都選擇了犧牲強(qiáng)一致性,保證可用性和分區(qū)容錯性,以及最終一致性,Cassandra 也是如此

      ACID

      傳統(tǒng)關(guān)系數(shù)據(jù)庫用 ACID 來保證強(qiáng)一致性, 這個 Cassandra 是做不到的

      A: Atomicity,原子性
      C: Consistency,一致性
      I: Isolation,隔離性
      D: Durability,持久性

      BASE

      大多數(shù) NOSQL 系統(tǒng)采用的方式

      BA:Basically Available,基本可用
      S:Soft State,軟狀態(tài),即中間可能不一致的狀態(tài)
      E:Eventually Consistent,最終一致性

      分布式哈希表和一致性哈希

      DHT-distributed hash table 分布哈希表, 一種去中心化的分布式系統(tǒng), 提供類似于哈希表查找服務(wù), 鍵值對存儲在DHT中, 任何參于的節(jié)點(diǎn)都可根據(jù) key 來存儲相應(yīng)的值

      DHT的特點(diǎn)是

      1. 獨(dú)立自主性: 各個節(jié)點(diǎn)各自為戰(zhàn), 不需要中央的協(xié)調(diào)和控制節(jié)點(diǎn)
      2. 容錯性: 任何一個節(jié)點(diǎn)加入,離開或損毀, 系統(tǒng)依然可用
      3. 可擴(kuò)展性: 可以任意增加節(jié)點(diǎn)以提高系統(tǒng)容量

      打個比方, 我有一籃12個雞蛋, 可以放在三個籃子里
      用最簡單的取余法, 將雞蛋編號0~17除以3, 每個籃子里放4個雞蛋
      假如增加或減少一個籃子, 都不是問題, 我只要根據(jù)編號取余一下子就能確定地找到那個雞蛋
      當(dāng)然這里的取余法太 low 了, 雖然數(shù)據(jù)分布絕對均勻, 但是一旦增減籃子我們就需要移動雞蛋來滿足約束條件

      一致性哈希就是比取余法更高級點(diǎn)的哈希算法, 一致性表示即使有籃子的增減, 無需移動數(shù)據(jù)依然可以根據(jù)編號確定地找到想找的雞蛋, 并且通過虛擬節(jié)點(diǎn)技術(shù)使得數(shù)據(jù)分布也比較均勻

      舉例如下

      
      package com.github.walterfan.util;
      
      import org.apache.commons.logging.Log;
      import org.apache.commons.logging.LogFactory;
      
      import java.security.MessageDigest;
      import java.security.NoSuchAlgorithmException;
      import java.util.Collection;
      import java.util.Map;
      import java.util.SortedMap;
      import java.util.TreeMap;
      
      
      
      interface HashFunction {
          Integer hash(String keyStr);
      }
      
      class MD5Hash implements HashFunction {
      
          public Integer hash(String keyStr) {
              byte[] bKey=mac("MD5", keyStr);
              return ((int) (bKey[3] & 0xFF) << 24)
                      | ((int) (bKey[2] & 0xFF) << 16)
                      | ((int) (bKey[1] & 0xFF) << 8)
                      | (bKey[0] & 0xFF);
          }
      
      
          public static byte[] mac(String alga, String str) {
              MessageDigest md;
              try {
                  md = MessageDigest.getInstance(alga);
                  return md.digest(str.getBytes());
              } catch (NoSuchAlgorithmException e) {
                  throw new IllegalArgumentException(e);
              }
      
          }
      
      }
      
      public class ConsistentHash<T> {
          private static Log logger = LogFactory.getLog(ConsistentHash.class);
          private final HashFunction hashFunction;
          private final int numberOfReplicas;
          private final SortedMap<Integer, T> circle = new TreeMap<Integer, T>();
      
          public ConsistentHash(HashFunction hashFunction, int numberOfReplicas,
                                Collection<T> nodes) {
              this.hashFunction = hashFunction;
              this.numberOfReplicas = numberOfReplicas;
      
              for (T node : nodes) {
                  add(node);
              }
          }
      
          public void add(T node) {
              for (int i = 0; i < numberOfReplicas; i++) {
                  circle.put(hashFunction.hash(node.toString() + i), node);
              }
          }
      
          public void remove(T node) {
              for (int i = 0; i < numberOfReplicas; i++) {
                  circle.remove(hashFunction.hash(node.toString() + i));
              }
          }
      
          public T get(String keyStr) {
              if (circle.isEmpty()) {
                  return null;
              }
              int hash = hashFunction.hash(keyStr);
      
              if (!circle.containsKey(hash)) {
                  SortedMap<Integer, T> tailMap = circle.tailMap(hash);
                  hash = tailMap.isEmpty() ? circle.firstKey() : tailMap
                          .firstKey();
              }
              return circle.get(hash);
          }
      
          public String toString() {
              StringBuilder sb = new StringBuilder("");
              for(Map.Entry<Integer, T> entry : circle.entrySet()) {
                  sb.append(entry.getKey());
                  sb.append("=");
                  sb.append(entry.getValue());
                  sb.append("\n");
              }
              return sb.toString();
          }
      
          /**
           * @param args
           */
          public static void main(String[] args) {
              java.util.List<String> nodes = new java.util.ArrayList<String>(3);
              nodes.add("1");
              nodes.add("2");
      
              ConsistentHash<String> continuum = new ConsistentHash<String>(new MD5Hash(), 8, nodes);
              String strID = "16580";
      
              String node = continuum.get(strID);
              System.out.println("select node: " + node + " for " + strID);
      
              java.util.Map<String, Integer> statMap = testDistribution(continuum);
              System.out.println(statMap);
      
              continuum.add("3");
              node = continuum.get(strID);
              System.out.println("add node 3, select node: " + node + " for " + strID);
      
              java.util.Map<String, Integer> statMap1 = testDistribution(continuum);
              System.out.println(statMap1);
      
              continuum.remove("3");
              node = continuum.get(strID);
              System.out.println("remove node 3, select node: " + node + " for " + strID);
              java.util.Map<String, Integer> statMap2 = testDistribution(continuum);
              System.out.println(statMap2);
          }
      
          private static java.util.Map<String, Integer> testDistribution(
                  ConsistentHash<String> continuum) {
              java.util.Map<String, Integer> statMap = new java.util.HashMap<String, Integer>();
      
              for(int i = 10000; i < 20000; i++) {
                  String svr = continuum.get("server" + i);
                  //System.out.println(i + ". server: " + svr);
                  Integer cnt = statMap.get(svr);
                  if(null == cnt) {
                      statMap.put(svr, 1);
                  } else {
                      statMap.put(svr, cnt + 1);
                  }
              }
              return statMap;
          }
      
      }
      
      
      
      

      輸出如下

      select node: 2 for 16580
      {1=5891, 2=4109}
      add node 3, select node: 2 for 16580
      {1=4703, 2=2517, 3=2780}
      remove node 3, select node: 2 for 16580
      {1=5891, 2=4109}
      
      

      安裝

      brew install cassandra22

      工具

      cqlsh

      ./cqlsh 192.168.3.5 -u test - pass
      

      node tool

      ./nodetool -h 192.168.3.5 ring
      

      nodetool status

      Datacenter: datacenter1
      =======================
      Status=Up/Down
      |/ State=Normal/Leaving/Joining/Moving
      --  Address    Load       Tokens       Owns (effective)  Host ID                               Rack
      UN  127.0.0.1  1015.55 KB  256          100.0%            9ec3a333-81bc-4945-9db1-ef1a13b62cde  rack1
      

      CQL

      類似 SQL , 詳細(xì)語法參見 http://docs./en/dse/5.1/cql/cql/cql_reference/cql_commands/cqlCommandsTOC.html

      SELECT * from system.schema_keyspaces limit 10;
      SELECT * from system.schema_columnfamilies limit 10;
      SELECT * from system.schema_columns limit 10;
      

      創(chuàng)建一個表空間

      CREATE KEYSPACE pims 
        WITH REPLICATION = { 
         'class' : 'NetworkTopologyStrategy', 
         'datacenter1' : 1 
        } ;
      

      架構(gòu)及特點(diǎn)

      Cassandra 寫的時候是將數(shù)據(jù)追加到可用節(jié)點(diǎn)的 commit log 上, 因而速度很快

      1. 將數(shù)據(jù)追加到 commit log 上
      2. 更新內(nèi)存的數(shù)據(jù)結(jié)構(gòu) memTable
      3. 內(nèi)存數(shù)據(jù)如果超過了最大限值, 則儲存到磁盤上的 SSTable 中

      相比之下, Cassandra 讀的速度比較慢, 因為它要根據(jù)主鍵至少讀取兩個節(jié)點(diǎn), 經(jīng)過數(shù)據(jù)比較后得出結(jié)果

      參見 Cassandra Architecture in brief

      Gossip 協(xié)議

      流言協(xié)議, 俗話說, 流言蜚語, 一傳十, 十傳百, 盡人皆知. Gossip 協(xié)議就是采用了類似的方法將消息迅速從一個結(jié)點(diǎn)復(fù)制到其他結(jié)點(diǎn). 傳遞時需要注意的就是傳遞的廣度和深度, 不要造成回環(huán)

      具體實現(xiàn)可參見 https://github.com/apache/incubator-gossip

      Gossiper 類隨機(jī)選擇一個節(jié)點(diǎn)來發(fā)送消息 GossipDigestSyncMessage, 接收消息節(jié)點(diǎn)發(fā)回確認(rèn)消息, 發(fā)送節(jié)點(diǎn)回應(yīng), 這輪消息同步即完成 (send-receive-ack), 如果同步失敗, 則將此節(jié)點(diǎn)標(biāo)記為可疑節(jié)點(diǎn), 連續(xù)發(fā)生同步失敗則可認(rèn)為此節(jié)點(diǎn)已經(jīng)掛掉了, 具體算法為 Phi Accural Failure Detection.

      核心結(jié)構(gòu)

      Node 節(jié)點(diǎn)

      也就是你存儲數(shù)據(jù)的地方, 一般我們至少部署三臺Cassandra 節(jié)點(diǎn)
      在讀寫的時候同時向三臺節(jié)點(diǎn)發(fā)出請求, 任意兩臺返回響應(yīng)即可

      N < W + R
      N 為復(fù)制的節(jié)點(diǎn)數(shù)
      W 為寫數(shù)據(jù)的最少返回節(jié)點(diǎn)數(shù)
      R 為讀數(shù)據(jù)的最少返回節(jié)點(diǎn)數(shù)

      3 < 2 + 2
      

      如果是 7 臺節(jié)點(diǎn), 復(fù)制因子設(shè)為3, 根據(jù)key 哈希過后會找到三臺結(jié)點(diǎn),依然是

      3 < 2 + 2
      

      復(fù)制因子設(shè)為4, 那就是7 < 4 + 4, 不過一般復(fù)制到三個結(jié)點(diǎn)也就夠了

      datacenter 數(shù)據(jù)中心

      一組相關(guān)節(jié)點(diǎn)的集合, 可以是物理上的一個數(shù)據(jù)中心, 也可以是虛擬的數(shù)據(jù)中心
      一般我們認(rèn)為不同的數(shù)據(jù)中心應(yīng)該位于不同的網(wǎng)絡(luò)位置. 一個數(shù)據(jù)中心內(nèi)的節(jié)點(diǎn)是在同一個網(wǎng)段中的

      Cluster 集群

      A cluster contains one or more datacenters. It can span physical locations.
      一個集群包含一個或多個數(shù)據(jù)中心, 它可能會跨越多個物理位置.

      Commit log 提交Log

      All data is written first to the commit log for durability. After all its data has been flushed to SSTables, it can be archived, deleted, or recycled.

      所有的數(shù)據(jù)都會先寫到commit log中持久化, 當(dāng)數(shù)據(jù)被刷新到 SSTables 后, 相關(guān)的commit log可以被歸檔,刪除或回收

      Table 表

      類似于關(guān)系數(shù)據(jù)庫, 表就是行的集合, 行由列組成, 列又分為主鍵和值

      SSTable 排序字串表

      排序的字符串表(SSTable)是一種不可變的數(shù)據(jù)文件, Cassandra定期向其寫入memtable。 SSTables僅可追加數(shù)據(jù), 按順序存儲在磁盤上,Cassandra為每個表保留一張 SSTable.

      Cassandra

      數(shù)據(jù)模型

      Cassandra RDBMS
      Key primary key
      Column family table
      Keyspace database
      Cluster server

      Cassandra 的 data model 設(shè)計與關(guān)系數(shù)據(jù)庫大為不同, 在設(shè)計模型不能完全照搬傳統(tǒng)關(guān)系型數(shù)據(jù)庫的那一套

      1. 不用想方設(shè)法減少寫次數(shù)

      在cassandra 中對于大量的寫操作有所優(yōu)化, 效率很高, 相比之下, 讀操作更加耗時

      1. 不用想方設(shè)法減少重復(fù)數(shù)據(jù)

      磁盤空間不是大問題, 與其遵循數(shù)據(jù)庫范式千方百計地減少重復(fù)次數(shù), 不如增加冗余以減少讀的次數(shù)

      除此之外, Cassandra 沒有 Join 操作, 這個在分布式架構(gòu)下這也絕非我們想要做的

      基本目標(biāo)

        1. 在集群中均勻分布數(shù)據(jù)

      記錄是按照 primary key 的第一個元素 partition key 的哈希在集群中分布的, 所以要挑選一個易于均勻分布的 primary key

        1. 盡量減少跨分區(qū)讀數(shù)據(jù)

      分區(qū)是一組行記錄的集合, 共享相同的partition key , 當(dāng)你執(zhí)行一個查詢時, 你要盡可能從盡量少的分區(qū)中讀取

      這兩條原則看起來有一點(diǎn)點(diǎn)矛盾, 第一條是針對寫,第二條是針對讀,在設(shè)計數(shù)據(jù)結(jié)構(gòu)時要做好平衡和取舍

      數(shù)據(jù)重復(fù)不是問題, 數(shù)據(jù)結(jié)構(gòu)可以靈活, 只能根據(jù) Key 進(jìn)行查詢
      在設(shè)計數(shù)據(jù)模型時可以按以下步驟

      步驟1: 根據(jù)需求, 把查詢和修改哪些數(shù)據(jù)一一列舉出來
      數(shù)據(jù)是查詢多還是修改多, 查詢多的數(shù)據(jù)最好放在一個分區(qū)里, 修改多的數(shù)據(jù)最好放在不同的分區(qū)中

      步驟2: 創(chuàng)建表時盡量使查詢和讀取落在一個分區(qū)里,寧愿多寫一點(diǎn),也不要跨區(qū)或表讀取

      注意事項

      我們在使用 Cassandra Driver 提供的 CQL 時, 常錯誤地和 SQL 搞混了
      注意

      1. Insert == Update , 所有的插入和修改本質(zhì)上都是 Set

      2. 由于 Cassandra 沒有行級鎖,如何處理并發(fā)情況下的競態(tài)條件(race condition) 呢?
        一是寫完以后于讀一下, 如果比較之后發(fā)現(xiàn)不是當(dāng)初寫的, 直接向客戶端報錯, 提示沖突, 寫入不成功
        二是使用 Cassandra 2.0 之后提供的輕量級事務(wù), 比如

      INSERT INTO USERS (login, email, name, login_count)
      values ('jbellis', 'jbellis@', 'Jonathan Ellis', 1)
      IF NOT EXISTS
      And an an example of resetting his password transactionally:
      
      UPDATE users
      SET reset_token = null, password = ‘newpassword’
      WHERE login = ‘jbellis’
      IF reset_token = ‘some-generated-reset-token’
      

      Cassandra 的技術(shù)細(xì)節(jié)和內(nèi)部實現(xiàn)再另行研究總結(jié), 這里就此打住.

      參考資料

      客戶端配置

      • Address: 127.0.0.1:9042
      • Username
      • Password
      • LocalDataCenter
      • ConsistencyLevel
      • Keyspace
      • RetryPolicy
      • ReadTimeout
      • ConnectTimeout

      Cassandra ConsistencyLevel

      • ANY
      • ONE
      • TWO
      • THREE
      • QUORUM
      • ALL
      • LOCAL_QUORUM
      • EACH_QUORUM
      • SERIAL
      • LOCAL_SERIAL
      • LOCAL_ONE

      驅(qū)動

      Java Driver

      <dependency> 
      <groupId>com.datastax.cassandra</groupId> 
      <artifactId>cassandra-driver-core</artifactId> 
      <version>3.1.2</version>
      </dependency>
      
      
      <dependency> <groupId>com.datastax.cassandra</groupId> 
      <artifactId>cassandra-driver-mapping</artifactId> 
      <version>3.1.2</version>
      </dependency>
      
      
      <dependency> 
      <groupId>com.datastax.cassandra</groupId> 
      <artifactId>cassandra-driver-extras</artifactId> 
      <version>3.1.2</version>
      </dependency>
      

      Python Driver

      Cassandra源碼:

      git clone http://git-wip-us./repos/asf/cassandra.git
      

      相關(guān)鏈接

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多