Redis3.0叢集crc16演算法php用戶端實現方法(php獲得redis3.0叢集中redis資料所在的redis分區插槽,並根據分區插槽取得分區所在redis伺服器位址)

來源:互聯網
上載者:User
Redis3.0叢集crc16演算法php用戶端實現方法(php取得redis3.0叢集中redis資料所在的redis分區插槽,並根據分區插槽取得分區所在redis伺服器位址)

資料分區

Redis叢集將資料分區後儲存在多個節點上,即不同的分區儲存在不同的節點上,每個節點可以儲存多個分區。每個分區在Redis中也被稱為“hash slot”,Redis叢集中總共規划了16384個分區。

例如:當叢集中有3個節點時,節點A將包含0-5460分區,節點B將包含5461-10922分區,節點C將包含10923-16383分區。

每個key將會儲存到一個唯一的分區中,每個分區其實就是一組key的集合,兩者對應關係為:key的CRC16校正碼%16384=hash slot(分區標記).可見Redis並沒有像Memecache一樣使用一致性雜湊。社區說採用此規則的key分布是相當的均勻,在我們的測試中也印證了這一點。

在Redis叢集中添加或者移除一個節點時相當容易的事情。例如:添加新節點D時,需要做的只是從A、B、C節點中移動一些分區給D。類似的,移除A時,只需將原屬A的分區移動給B和C,等A變空時移除即可。

節點間的分區移動不需要停止服務,所以添加節點、移除節點或者改變節點的分區數量不需要停止叢集服務。

用戶端訪問叢集時,理論上可以訪問叢集中的任一節點。此時,被訪問的資料可能不存在於被訪問的節點中,但是被訪問節點能自動獲知目標節點,並重新導向用戶端的訪問,即將目標節點地址返回給用戶端,用戶端再次發起訪問請求。當然,好的用戶端工具應該實現資料分區和節點對應關係的緩衝,並在對應關係發生改變時能自動更新。目前,包括Jedis在內的幾個用戶端工具已經實現了此功能。

CRC概念

CRC基本原理不懂的,請移步維基百科:循環冗餘檢查碼

通常根據CRC校正碼的位元(也等於產生多項式【G(x)】最高的冪次)的不同來區分不同的CRC演算法,如CRC-1、CRC-8、CRC-16等。冪次相同的情況下,不同的標準也有不同的CRC演算法。比如G(x)最高次冪為16的時候有:CRC-16-CCITT、CRC-16-IBM等。Redis使用的是CRC-16-CCITT標準,即G(x)為:x16 + x12 + x5 + 1 。

G(x)的通常表徵方式是將多項式轉換成二進位: 1 0001 0000 0010 0001。用十六進位表示為:0x11021。該數儲存空間是17位(2個位元組+1個位,C語言實際儲存是3個位元組),實際上,在模二除的時候,被除數的最高位 1 和除數最高位 1 總是對齊的,其異或結果,總為0,故可省略,則G(x) = 0x1021(2個位元組),節省了一個位元組的空間。 摘取天上星 原創,轉載請標明作者出處


源碼

redis的src目錄下的 crc16.c檔案:

static const uint16_t crc16tab[256]= {    0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,    0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,    0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,    0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,    0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,    0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,    0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,    0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,    0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,    0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,    0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,    0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,    0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,    0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,    0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,    0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,    0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,    0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,    0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,    0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,    0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,    0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,    0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,    0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,    0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,    0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,    0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,    0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,    0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,    0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,    0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,    0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0};uint16_t crc16(const char *buf, int len) {    int counter;    uint16_t crc = 0;    for (counter = 0; counter < len; counter++)            crc = (crc<<8) ^ crc16tab[((crc>>8) ^ *buf++)&0x00FF];    return crc;}

前文提到了CRC校正碼不同的機構有不同的標準,這裡Redis遵循的標準是CRC-16-CCITT標準,這也是被XMODEM協議使用的CRC標準,所以也常用XMODEM CRC代指。

該段代碼的演算法原理並不是作者首創的,這是比較經典的“基於位元組查表法的CRC校正碼產生演算法”(本文為"摘取天上星"周末實操所得,完全可用!)

php用戶端實現redis crc16驗證標準的方法.

function redisCRC16 (&$ptr){    $crc_table=array(    0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,    0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,    0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,    0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,    0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,    0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,    0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,    0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,    0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,    0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,    0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,    0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,    0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,    0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,    0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,    0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,    0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,    0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,    0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,    0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,    0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,    0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,    0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,    0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,    0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,    0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,    0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,    0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,    0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,    0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,    0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,    0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0    );    $crc = 0x0000;    for ($i = 0; $i < strlen($ptr); $i++)        $crc =  $crc_table[(($crc>>8) ^ ord($ptr[$i]))] ^ (($crc<<8) & 0x00FFFF);    return $crc;}$test = chr(0xC6).chr(0xCE).chr(0xA2).chr(0x03); // CRC16-CCITT = 0xE2B4$key1='key1'; $key2='key2';$key3='key3';echo $key1_db=redisCRC16($key1)%16384; //得出在redis(叢集)中索引值為'key1'的資料存放區插槽為9189echo "
";echo $key2_db=redisCRC16($key2)%16384; //得出在redis(叢集)中索引值為'key2'的資料存放區插槽為4998echo "
";echo $key3_db=redisCRC16($key3)%16384; //得出在redis(叢集)中索引值為'key3'的資料存放區插槽為935

根據crc16演算法取得的redis資料分區插槽取得 分區所在伺服器位址:

首先我們先看一下本地叢集環境中的redis分區插槽區間範圍(cd 切換到redis安裝包目錄下的src目錄[注意:redis解壓包包非安裝後的程式所在目錄位址]):

[[email protected] src]$  ./redis-trib.rb check 127.0.0.1:6384Connecting to node 127.0.0.1:6384: OKConnecting to node 127.0.0.1:6381: OKConnecting to node 127.0.0.1:6383: OKConnecting to node 127.0.0.1:6379: OKConnecting to node 127.0.0.1:6380: OKConnecting to node 127.0.0.1:6382: OK>>> Performing Cluster Check (using node 127.0.0.1:6384)S: 91329dacb2ac77d9295ed46ecaaec6f2c415f7f6 127.0.0.1:6384   slots: (0 slots) slave   replicates 0be8c0b96e23a5843ece9d86cb6d287c92529a8cM: 0be8c0b96e23a5843ece9d86cb6d287c92529a8c 127.0.0.1:6381   slots:10923-16383 (5461 slots) master   1 additional replica(s)S: 53926c1f8b757c6db2d53e12ee94b8c1a761e663 127.0.0.1:6383   slots: (0 slots) slave   replicates beff88cb6dcf6897a6c6de36350032984a4bdf33M: 2fb7a8edab2038d7fabe305dd0099de8bdf1f1e6 127.0.0.1:6379   slots:0-5460 (5461 slots) master   1 additional replica(s)M: beff88cb6dcf6897a6c6de36350032984a4bdf33 127.0.0.1:6380   slots:5461-10922 (5462 slots) master   1 additional replica(s)S: 4738074195072ae29c3f3160382e97c3b56a6392 127.0.0.1:6382   slots: (0 slots) slave   replicates 2fb7a8edab2038d7fabe305dd0099de8bdf1f1e6[OK] All nodes agree about slots configuration.>>> Check for open slots...>>> Check slots coverage...[OK] All 16384 slots covered.

以上內容可以看到M位主,S為從(官方要求的redis叢集環境必須為6台以上偶數形式的伺服器數量,否則無法建立叢集環境)從上面輸出可以看到分區插槽所在伺服器位置: slots:10923-16383 (5461 slots) 127.0.0.1:6381 對應從機 地址為127.0.0.1:6384slots:0-5460 (5461 slots) 127.0.0.1:6379 master 對應從機 地址為127.0.0.1:6381slots:5461-10922 (5462 slots) 127.0.0.1:6380 master對應從機 地址為:127.0.0.1:6383
一共三台主要磁碟分割,可以通過 取得的插槽位置 定位到 不同的redis分區上去取對應的資料,一但主要磁碟分割數量有變動,就需要根據實際分區數量重新置放插槽分區範圍存取redis地址根據ceil(redisCRC16(redis $key值)%16384 / intval(16384/叢集master數)) 得到 對應 的 redis叢集伺服器順序 地址,並根據對應區間地址指向到對應的 redis區間master地址即可,注意:如果對應的master區間掛掉了,也不必擔心,只需要將地址變更為master主區間對應的 slave從區間伺服器位址即可一樣取得redis資料,而這正是redis3.0後續版本的精妙之處,不需要第三方外掛程式即可在服務端制動實現叢集主備模式,不會影響使用者正常讀取,當然如果是master和對應的slave一起掛掉了那就沒辦法了,通常這種幾率是很小很小的 小到可以忽略即可...關於redis添加刪除叢集節點的方法請參閱相關資料,摘取天上星 原創,轉載請標明作者出處,本文暫不詳敘!

  • 相關文章

    聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.