redis分布式方案redis cluster的介绍和实践
簡要介紹
redis cluster是redis官方提供的分布式解決方案。主要作用有兩點:
分布式的方案要解決把整個數據集按照分區規則映射到多個節點的問題,即把數據集劃分到多個節點上,每個節點負責整體數據的一個子集。
Redis Cluser采用的分區方案叫做虛擬槽分區,所有數據的鍵值根據哈希函數映射到0~16383整數槽內,計算式:slot=CRC16(key)&16383。所有的槽(slot)分布到各個節點上,根據數據的鍵值計算所屬的槽確定其存儲在哪一個集群的節點中。
接下來部署一個簡單的redis cluster,通過部署的過程理解redis cluster到底是怎么回事以及怎么使用。
拓撲結構
redis cluster因為是分布式方案,自然要求多個節點。另外為了保證集群的高可用性,會給每一個主節點配置一個或者多個從節點。主節點故障時從節點可以自動替換上去,不至于因為單個節點的故障而導致集群的故障。
接下來我們使用docker部署6個redis節點組成的redis cluster,三主三從。因為在同一臺機器上模擬,所以節點的區別主要體現在端口不一致。下文各個節點名稱分別使用 “redis-端口號” 來區分。
每個節點的相關信息如下:
| redis-6380 | 主節點6380 | 6380 | redis-6380.conf nodes-6380.conf |
| redis-6381 | 主節點6381 | 6381 | redis-6381.conf nodes-6381.conf |
| redis-6382 | 主節點6382 | 6382 | redis-6382.conf nodes-6382.conf |
| redis-6383 | 從節點6383(所屬主節點6380) | 6383 | redis-6383.conf nodes-6383.conf |
| redis-6384 | 從節點6384(所屬主節點6381) | 6384 | redis-6384.conf nodes-6384.conf |
| redis-6385 | 從節點6385(所屬主節點6382) | 6385 | redis-6385.conf nodes-6385.conf |
其拓撲結構如下:
部署redis cluster過程
redis創建
redis本身內置提供cluster的功能。不需要額外安裝其他組件。redis部署的時候和單機的redis部署并沒有太大的區別,主要區別體現在配置文件當中的cluster部分配置要打開。如下給出了 6380 節點的配置。其他節點也只要修改相應的地址和端口信息即可。
redis-6380.conf:
# 節點端口 port 6380 # 開啟集群模式 cluster-enabled yes # 節點超時時間,單位毫秒 cluster-node-timeout 15000 # 集群內部配置文件,這份配置文件會記錄集群當中的節點信息。由redis自動維護,不要手動去修改,防止破壞集群的相關配置。 cluster-config-file "nodes-6380.conf" #主節點密碼,部分節點會成為從節點 masterauth password使用docker部署各個容器,命令如下:
尤其要注意的是redis使用docker部署集群的時候必須使用host模式。
docker run --net=host --name redis-6380 -v /data/redis-cluster/conf/redis-6380.conf:/usr/local/etc/redis/redis.conf -v /data/redis-cluster/conf/nodes-6380.conf:/data/nodes-6380.conf -d 192.168.168.98:5000/redis redis-server /usr/local/etc/redis/redis.confdocker run --net=host --name redis-6381 -v /data/redis-cluster/conf/redis-6381.conf:/usr/local/etc/redis/redis.conf -v /data/redis-cluster/conf/nodes-6381.conf:/data/nodes-6381.conf -d 192.168.168.98:5000/redis redis-server /usr/local/etc/redis/redis.confdocker run --net=host --name redis-6382 -v /data/redis-cluster/conf/redis-6382.conf:/usr/local/etc/redis/redis.conf -v /data/redis-cluster/conf/nodes-6382.conf:/data/nodes-6382.conf -d 192.168.168.98:5000/redis redis-server /usr/local/etc/redis/redis.confdocker run --net=host --name redis-6383 -v /data/redis-cluster/conf/redis-6383.conf:/usr/local/etc/redis/redis.conf -v /data/redis-cluster/conf/nodes-6383.conf:/data/nodes-6383.conf -d 192.168.168.98:5000/redis redis-server /usr/local/etc/redis/redis.confdocker run --net=host --name redis-6384 -v /data/redis-cluster/conf/redis-6384.conf:/usr/local/etc/redis/redis.conf -v /data/redis-cluster/conf/nodes-6384.conf:/data/nodes-6384.conf -d 192.168.168.98:5000/redis redis-server /usr/local/etc/redis/redis.confdocker run --net=host --name redis-6385 -v /data/redis-cluster/conf/redis-6385.conf:/usr/local/etc/redis/redis.conf -v /data/redis-cluster/conf/nodes-6385.conf:/data/nodes-6385.conf -d 192.168.168.98:5000/redis redis-server /usr/local/etc/redis/redis.conf6個redis容器部署完成
進入其中一個容器當中,使用cluster nodes命令查看cluster的節點信息。也可以使用cluster info查看集群的狀態。
可見當前的redis cluster中只有一個節點。各個節點還需要通過握手的過程相互通信,然后組成一個可以相互通信的集群。
握手
節點握手是指一批運行在集群模式下的節點通過Gossip協議彼此通信,達到感知對方的過程。節點握手是集群彼此通信的第一步,由客戶端發起命令:cluster meet {ip} {port}。
登錄到其中的一個節點中,使用cluster meet將所有的節點連接起來。
再來看節點信息,可見6個節點全部能夠發現了。
分配槽
前面說了,redis cluster根據分區規則將數據分布到不同的redis節點上,降低單個redis節點的讀寫壓力。
redis cluster將數據的分區分為16384個槽,數據存取的時候根據哈希算法將key值計算出對應的值(0-16383),然后去對應的槽里取值。這16384個槽需要全部分配到redis節點上,如果有槽沒有分配,則redis不能夠使用。
接下來將槽分配到我們部署的三個主節點中。
redis-cli -h 127.0.0.1 -p 6380 -a password cluster addslots {0..5461} redis-cli -h 127.0.0.1 -p 6381 -a password cluster addslots {5462..10924} redis-cli -h 127.0.0.1 -p 6382 -a password cluster addslots {10925..16383}再來看節點信息,可以看見三個主節點信息末尾多了分配的槽的信息。
設置從節點
為了保證集群的高可用性,每個redis主節點需要設置從節點。登錄從節點,使用cluster replicate命令設置其所屬主節點,主節點的標識是cluster nodes結果中給redis節點生成的標識。這個標識同樣會寫在cluster-config-file文件中,這個文件不刪除,redis啟動的時候會去這個文件中讀取標識和集群信息繼續使用。
redis-cli -h 127.0.0.1 -p 6383 -a password cluster replicate 389c66679b44ea421ac685b3b44b64e9a7a32e5c redis-cli -h 127.0.0.1 -p 6384 -a password cluster replicate e65d837c859c8ad19ee1962829ee7e9fa20cdfc7 redis-cli -h 127.0.0.1 -p 6385 -a password cluster replicate 0304888a12fe7f7fae5df5f444cc4a8832e8d170再看cluster nodes節點信息,可見redis-6383,redis-6384,redis-6885三個節點都顯示為slave,并且有所屬的主節點的標識信息。
至此,一個簡單的redis-cluster搭建完成。它由6個節點構成,redis-6380,redis-6381,redis-6382這3個主節點負責處理槽和相關數據,redis-6383,redis-6384,redis-6385這3個從節點負責故障轉移。
連接測試
前文說過,數據根據鍵值通過哈希算法計算得到0-16383的整數值,這些slot已在分配槽的過程當中分配到不同的節點。
根據 cluster keyslot {key}可以計算鍵值的哈希值。
前文slot分配如下
| redis-6380 | 0…5461 |
| redis-6381 | 5462…10924 |
| redis-6382 | 10925…16383 |
key為“name”的數據所屬slot為5798,數據會在redis-6381當中存儲。
如果在別的節點操作數據,會得到 MOVED 的結果,顯示該數據應該存儲在哪個節點。
在redis-6381執行數據的存儲
也可以使用 redis-cli -c加上參數登錄redis客戶端,在數據存取節點不正確時,客戶端會自動做重定向。
接下測試一下主從節點的故障轉移,把 redis-6381 節點停掉。redis-6384是其從節點,觀察日志可以看出,剛開始是連接失敗,而后redis-6384成為了主節點,替代redis-6381繼續提供服務。
查看各個節點的狀態,可見redis-6384成為了主節點并且將分配給redis-6381的槽“5462-10924”分配給了redis-6384。同時數據也轉移到了redis-6384上。
將redis-6381節點啟動,查看集群節點信息,如下圖??梢娭匦聠拥墓濣c自動成為了redis-6384的從節點,作為故障轉移的備用節點。
使用redis-trib.rb搭建集群
redis-trib.rb是redis官方提供的一個工具,在redis的源碼包的src目錄下??梢韵螺d源碼包獲得該工具
wget http://download.redis.io/releases/redis-3.0.6.tar.gz
該工具是使用ruby開發的,使用該工具前需要安裝ruby的環境
sudo apt-get install ruby
我安裝了這個工具之后會出現一些使用上的問題,應該是我安裝的問題。建議可以下載一個redis-trib.rb 的docker鏡像來使用。
當redis-trib.rb可使用后,我們講講這個工具的使用方法。
使用redis-trib.rb創建集群之前同樣要先準備好各個redis節點。同我們手工配置的方式一致,提供各個節點的配置文件,然后創建各個節點。配置文件和創建節點的方式前面已經講述。
有幾點區別以及注意事項:
準備好各個節點之后,我們使用redis-trib.rb創建集群,命令如下:
redis-trib.rb create --replicas 1 172.17.0.1:6380 172.17.0.1:6381 172.17.0.1:6382 172.17.0.1:6383 172.17.0.1:6384 172.17.0.1:6385--replicas 1表示每個節點有一個從節點,redis-trib.rb會自動分配主從關系。
執行結果如下:
可見一個命令就把我們之前做的 握手,分配槽,主從節點的配置等等工作都完成了。工具的使用非常方便。
我們可以繼續使用 cluster nodes查看節點信息
或者redis-trib.rb提供了check方法,檢查整個集群。
可見檢查結果顯示提示集群所有的槽都已分配到節點。
集群擴容和收縮
集群可對現有的拓撲結構進行調整,就是節點的新增和減少。下面講講集群擴容(新增節點)和收縮(減少節點)的方式。
擴容
擴容的操作步驟如下:
現在加入兩個新的redis節點,
| 主節點6386 | 6386 | redis-6386.conf nodes-6386.conf |
| 從節點6387(所屬主節點6386) | 6387 | redis-6387.conf nodes-6387.conf |
前兩個步驟不再贅述,和前面說的集群的搭建是一致的。
準備兩個節點的配置文件
創建docker容器
docker run --net=host --name redis-6386 -v /data/redis-cluster/conf/redis-6386.conf:/usr/local/etc/redis/redis.conf -v /data/redis-cluster/conf/nodes-6386.conf:/data/nodes-6386.conf -d 192.168.168.98:5000/redis redis-server /usr/local/etc/redis/redis.confdocker run --net=host --name redis-6387 -v /data/redis-cluster/conf/redis-6387.conf:/usr/local/etc/redis/redis.conf -v /data/redis-cluster/conf/nodes-6387.conf:/data/nodes-6387.conf -d 192.168.168.98:5000/redis redis-server /usr/local/etc/redis/redis.conf兩個新節點加入集群
cluster meet 172.17.0.1 6386 cluster meet 172.17.0.1 6387
新加入的節點如果是作為從節點使用,則直接給指定所屬主節點即可。
如果是要作為主節點分擔讀寫數據的壓力,那么需要做槽和數據的遷移。下面演示手動遷移指定槽 5798 的步驟
目標節點準備導入槽5798的數據
源節點準備導出槽5798數據
批量獲取槽5798對應的鍵
使用migrate批量遷移鍵
這里出現一個問題,因為6386設置了密碼,下面的結果會顯示無權限訪問。但是設置了密碼參數確顯示格式不對。所以我暫時把6386的密碼認證關了,進行的鍵遷移。
最后,通知所有主節點槽5798指派給目標節點6386
127.0.0.1:6386> cluster setslot 5798 node 30c5e546f7d2ced550057d6b113ed982301bcd33 127.0.0.1:6380> cluster setslot 5798 node 30c5e546f7d2ced550057d6b113ed982301bcd33 127.0.0.1:6384> cluster setslot 5798 node 30c5e546f7d2ced550057d6b113ed982301bcd33 127.0.0.1:6382> cluster setslot 5798 node 30c5e546f7d2ced550057d6b113ed982301bcd33然后可以在6386看到槽的分布,5798這個槽都分配給了6386。并且 name 這個值也遷移了過來
同樣的,可以將6387設置為6386的從節點
redis-cli -h 127.0.0.1 -p 6387 -a password cluster replicate 30c5e546f7d2ced550057d6b113ed982301bcd33
至此,集群的一個簡單擴容完成。
收縮
收縮就意味著把節點去掉。我們可以根據擴容的流程,反其道而行之即可?,F在我們把5798這個槽遷回6381。
#分別導出,導入5798槽127.0.0.1:6384> cluster setslot 5798 importing ccb75e92d2c4d99196cff6749e427207577f1e3b OK 127.0.0.1:6386> cluster setslot 5798 migrating 30c5e546f7d2ced550057d6b113ed982301bcd33 OK#將數據進行遷移 127.0.0.1:6386> migrate 172.17.0.1 6384 "" 0 5000 keys name OK#通知所有節點5798槽所屬的節點 127.0.0.1:6386> cluster setslot 5798 node ccb75e92d2c4d99196cff6749e427207577f1e3b 127.0.0.1:6380> cluster setslot 5798 node ccb75e92d2c4d99196cff6749e427207577f1e3b 127.0.0.1:6384> cluster setslot 5798 node ccb75e92d2c4d99196cff6749e427207577f1e3b 127.0.0.1:6382> cluster setslot 5798 node ccb75e92d2c4d99196cff6749e427207577f1e3b槽遷移完成之后,6386,6387節點就沒有了數據??梢允褂胏luster forget node-id移除出集群當中
127.0.0.1:6384> cluster forget 30c5e546f7d2ced550057d6b113ed982301bcd33 OK 127.0.0.1:6384> cluster forget b240523731efca286c9aff97d12e0794d49258a5 OK至此收縮完成。
redis-trib.rb的槽遷移
上面我們手動執行執行過集群的擴容和收縮。擴容和收縮的過程因為涉及到槽的遷移以及槽中數據遷移非常的復雜。幸好使用redis-trib.rb工具提供了槽的遷移功能,這里介紹一下。
以下命令可以容易的進行不同節點之間的槽遷移
docker run --rm -it zvelo/redis-trib reshard 172.17.0.1:6380 redis-trib.rb reshard host:port --from <arg> --to <arg> --slots <arg> --yes --timeout <arg> --pipeline <arg>命令的參數說明如下:
- host:port:必傳參數,集群內任意節點地址,用來獲取整個集群信息。
- –from:制定源節點的id,如果有多個源節點,使用逗號分隔,如果是all源節點變為集群內所有主節點,在遷移過程中提示用戶輸入。
- –to:需要遷移的目標節點的id,目標節點只能填寫一個,在遷移過程中提示用戶輸入。
- –slots:需要遷移槽的總數量,在遷移過程中提示用戶輸入。
- –yes:當打印出reshard執行計劃時,是否需要用戶輸入yes確認后再執行reshard。
- –timeout:控制每次migrate操作的超時時間,默認為60000毫秒。
- ·–pipeline:控制每次批量遷移鍵的數量,默認為10。
下面我們來測試一下,先看當前節點的槽分布:
例如我們要從redis-6382中遷移100個槽給redis-6381。執行命令如下
用redis-trib.rb執行命令的時候會有錯誤出現,是我安裝的工具的問題。于是我下了一個redis-trib的docker鏡像來執行這個命令
再查看各個節點的槽分布:
和上文遷移前的槽分布對比,可見redis-6382的槽少了100個,而redis-6381的節點多了100個。
客戶端連接
基本原理
客戶端初始化連接時,將redis cluster 的slot在各個節點中的分配情況獲取到并且保存在客戶端的緩存當中??蛻舳嗽趫绦袛祿脑鰟h查改時,首先計算鍵值的slot值,再根據slot值找到要操作的節點,獲取該節點的連接后執行數據的操作。
下面給出java連接redis cluster的示例代碼。
Jedis直接連接以及異常轉移測試
引入依賴,要注意早期版本的jedis不支持有密碼的cluster的操作。
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.9.0</version> </dependency>示例代碼:
package test; import java.util.HashSet; import java.util.Set; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisCluster;public class JedisClusterDemo {public static JedisCluster jedisCluster;public static void initJedisCluster() {Set<HostAndPort> hostAndPortsSet = new HashSet<HostAndPort>();hostAndPortsSet.add(new HostAndPort("172.17.0.1", 6380));hostAndPortsSet.add(new HostAndPort("172.17.0.1", 6381));hostAndPortsSet.add(new HostAndPort("172.17.0.1", 6382));hostAndPortsSet.add(new HostAndPort("172.17.0.1", 6383));hostAndPortsSet.add(new HostAndPort("172.17.0.1", 6384));hostAndPortsSet.add(new HostAndPort("172.17.0.1", 6385));hostAndPortsSet.add(new HostAndPort("172.17.0.1", 6386));hostAndPortsSet.add(new HostAndPort("172.17.0.1", 6387)); GenericObjectPoolConfig config = new GenericObjectPoolConfig();//參數: redis節點集合, 連接超時時間, 數據操作超時時間, 重試次數, 密碼, 連接池配置jedisCluster = new JedisCluster(hostAndPortsSet, 10000, 10000, 5, "password", config);}public static void main(String args[]) {initJedisCluster();int incre = 0;while (true) {try {incre++;Thread.currentThread().sleep(10000);jedisCluster.set("number"+incre, String.valueOf(incre));String value = jedisCluster.get("number"+incre);System.out.println(value);} catch (Exception e) {e.printStackTrace();} }} }控制臺顯示程序執行的結果:
查看各個redis節點可見數據分布在各個節點當中
然后我們停掉其中一個主節點模擬故障轉移
如下圖,可見redis-6384節點斷開了連接,redis-6381節點成為了主節點
而我們的程序會出現拒絕連接的異常,在故障轉移完成之后繼續正常運行
redis-6381中的數據正常,部分是從redis-6384節點中同步過來的
spring程序連接以及異常轉移測試
依賴配置
<dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>4.0.8.RELEASE</version> </dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>4.0.8.RELEASE</version> </dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>4.0.8.RELEASE</version> </dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.9.0</version> </dependency><dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-redis</artifactId><version>1.8.0.M1</version> </dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.8.4</version> </dependency>spring的配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"xmlns:cache="http://www.springframework.org/schema/cache http://www.springframework.org/schema/cachehttp://www.springframework.org/schema/cache/spring-cache.xsd"><!-- jedis連接池的配置 --> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig" > <property name="maxIdle" value="10000" /> <property name="maxWaitMillis" value="10000" /> <property name="testOnBorrow" value="true" /> </bean > <!-- cluster連接的配置, 注入各個節點 --><bean id="redisClusterConfiguration" class="org.springframework.data.redis.connection.RedisClusterConfiguration"><property name="clusterNodes"><set><bean id="clusterRedisNodes1" class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="172.17.0.1" /><constructor-arg name="port" value="6380" type="int" /></bean><bean id="clusterRedisNodes2" class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="172.17.0.1" /><constructor-arg name="port" value="6381" type="int" /></bean><bean id="clusterRedisNodes3" class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="172.17.0.1" /><constructor-arg name="port" value="6382" type="int" /></bean><bean id="clusterRedisNodes4" class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="172.17.0.1" /><constructor-arg name="port" value="6383" type="int" /></bean><bean id="clusterRedisNodes5" class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="172.17.0.1" /><constructor-arg name="port" value="6384" type="int" /></bean><bean id="clusterRedisNodes6" class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="172.17.0.1" /><constructor-arg name="port" value="6385" type="int" /></bean><bean id="clusterRedisNodes7" class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="172.17.0.1" /><constructor-arg name="port" value="6386" type="int" /></bean><bean id="clusterRedisNodes8" class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="172.17.0.1" /><constructor-arg name="port" value="6387" type="int" /></bean></set></property></bean><!-- 配置redis連接生成器,主要將cluster的節點信息和redis連接池配置作為構造函數參數注入。另外添加上主節點password的配置 --><bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" > <property name="password" value="password" /><property name="timeout" value="30000" ></property><constructor-arg name="clusterConfig" ref="redisClusterConfiguration"></constructor-arg><constructor-arg name="poolConfig" ref="poolConfig"></constructor-arg> </bean > <!-- RedisTemplate配置,提供一些數據的序列化和反序列化配置 --><bean id="keySerializer" class="org.springframework.data.redis.serializer.GenericToStringSerializer"><constructor-arg index="0" type="java.lang.Class" value="java.lang.Object" /></bean><bean id="serializer" class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"></bean><bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"><property name="connectionFactory" ref="connectionFactory" /><property name="defaultSerializer" ref="serializer" /><property name="keySerializer" ref="keySerializer" /><property name="hashKeySerializer" ref="keySerializer" /></bean> </beans>代碼示例:
public class Main {public static void main(String[] args) {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-redis.xml");RedisTemplate<String, String> template = (RedisTemplate<String, String>) context.getBean("redisTemplate");int incre = 0;while (true) {try {incre++;Thread.currentThread().sleep(3000); template.opsForValue().set("springnumber"+incre, String.valueOf(incre));String number = template.opsForValue().get("springnumber"+incre);System.out.println("key:"+("springnumber"+incre)+"; value:"+number);} catch (Exception e) {e.printStackTrace();}}} }程序的執行結果
各個redis節點中的數據分布如下:
模擬redis-6380的宕機,查看故障轉移的結果如下圖。可見redis-6380斷開了連接,而redis-6383節點接替了其繼續提供服務。
程序執行的輸出如下圖,也可看出出現了連接的異常,而后恢復正常。
查看redis-6383節點的數據正常
結論
redis cluster能夠正常的提供分布式以及高可用的解決方案。搭建時可以使用redis-trib.rb工具進行搭建,可以很大幅度的提高效率。
在對于已有的redis cluster進行擴容或者收縮時要慎重。在實驗過程當中出現過一些問題導致數據的丟失。
在使用redis cluster時,要注意客戶端jar包的差異。早期的jar包對于密碼的支持受限。
在使用redis cluster時也會存在一些限制。如每個節點只能使用db0,因為分布式存儲在不同節點,對于redis的事務支持和批量操作也僅限于同一個節點上。在使用時要注意這些問題。
總結
以上是生活随笔為你收集整理的redis分布式方案redis cluster的介绍和实践的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python分段函数求值域_函数定义域,
- 下一篇: xml 转json 传输