說明:仍然是偽叢集,所有的Redis節點,都在一個伺服器上,採用不同配置檔案,不同埠的形式實現
前提:已經安裝好了Redis,本文的redis的版本是redis-6.2.3
Redis的下載、安裝參考:https://www.cnblogs.com/rxx1005/p/15754565.html
文章中,Redis的安裝目錄為:/opt/app/redis/cluster/redis-6.2.3
本文使用到的工具:
前言
redis cluster 的兩種部署方式:
準備工作
將常用指令碼複製到bin目錄下
此步驟是個人習慣,可以不復制,後面使用命令時,直接使用src目錄的即可。
在編譯Redis之後,會在 redis的src目錄下生成一些指令碼
我把這些常用指令碼,使用 cp 命令,拷貝到 resdis 根目錄下的 bin 目錄下(bin目錄自己建立的)
安裝ruby(redis5.0之後不需要安裝)
此處可跳過!!! 我使用的是redis-6.2.3,建立叢集的時候,不再使用redis-trib.rb,而是用 redis-cli --cluster ,使用redis-cli
--cluster建立叢集,不需要安裝ruby,下面是安裝ruby的辦法。
注意:不要直接在Linux上執行 yum install ruby ,因為這樣安裝的ruby版本太低了
低版本redis搭建 cluster叢集,需要用到redis得src目錄下的 redis-trib.rb ,此指令碼需要依賴 ruby 語言,現安裝 ruby,在Linux上,直接使用wget
命令,下載ruby安裝包,也可以去官網下載之後,上傳到Linux,官網:http://www.ruby-lang.org/en/downloads/
[root@localhost conf]# wget https://cache.ruby-lang.org/pub/ruby/3.1/ruby-3.1.1.tar.gz
解壓,編譯,編譯約1~2分鐘
[root@localhost app]# tar -zxvf ruby-3.1.1.tar.gz
[root@localhost ruby-3.1.1]# cd ruby-3.1.1
[root@localhost ruby-3.1.1]# ./configure --prefix=/usr/local/ruby --enable-shared
[root@localhost ruby-3.1.1]# make & make install
新增環境變數:
編輯 /etc/profile 檔案,在檔案末尾加上以下內容
export RUBY_HOME=/usr/local/ruby
export PATH=$RUBY_HOME/bin:$RUBY_HOME/lib:$PATH
儲存,退出,重新載入檔案
[root@localhost ~]# source /etc/profile
執行 ruby -v,如果出現版本號,說明安裝成功
安裝redis庫
[root@localhost ruby-3.1.1]# gem install redis
至此,ruby就安裝好了。
自定義配置檔案叢集搭建
配置
在redis根目錄下,建立一個conf資料夾,並在conf資料夾下,建立6個資料夾,用於存叢集每個節點的配置檔案、資料檔案等
[root@localhost redis-6.2.3]# mkdir conf
[root@localhost redis-6.2.3]# cd conf/
[root@localhost conf]# mkdir 7001 7002 7003 7004 7005 7006
在 7001 資料夾內,建立一個redis 的配置檔案:
[root@localhost conf]# cd 7001/
[root@localhost 7001]# touch redis.conf
在 redis.conf 配置檔案內,加入以下配置:
# 將bind這一行註釋掉,或者修改為0:0:0:0,這表示任意地址都可以連線此Redis服務
# bind 127.0.0.1
# 關閉保護模式,如果開啟的話,外部客戶端就連不上Redis
protected-mode no
# 配置redis的埠號(不同節點使用不同的埠號)
port 7001
# 以守護程式執行(後臺執行redis)
daemonize yes
# 服務啟動後記錄執行緒號的檔案
pidfile "redis.pid"
# 日誌
logfile "/opt/app/redis/cluster/redis-6.2.3/conf/7001/log.log"
# 資料庫的個數
databases 16
# 設定資料儲存到資料檔案中的save規則,3600秒內修改1次key,進行一次磁碟儲存操作
save 3600 1
save 300 100
save 60 10000
# 指定儲存至本地資料庫時是否壓縮資料,預設是yes,redis採用LZF壓縮,需要消耗CPU資源
rdbcompression yes
# 儲存rdb檔案時,是否對rdb檔案進行校驗
rdbchecksum yes
# 儲存資料的檔名字
dbfilename "dump.rdb"
# 儲存資料的目錄,這個目錄需要提前建立出來
dir "/opt/app/redis/cluster/redis-6.2.3/conf/7001"
# 是否開啟aof持久化
appendonly yes
# aof檔名字
appendfilename "appendonly.aof"
# 叢集配置檔案,自動生成,不能人為維護
cluster-config-file "nodes.conf"
#開啟cluster叢集
cluster-enabled yes
#Redis叢集節點超時時限
cluster-node-timeout 15000
將這個配置檔案,複製5份到 7002 7003 7004 7005 7006 目錄下
[root@localhost 7001]# cp redis.conf ../7002/
[root@localhost 7001]# cp redis.conf ../7003/
[root@localhost 7001]# cp redis.conf ../7004/
[root@localhost 7001]# cp redis.conf ../7005/
[root@localhost 7001]# cp redis.conf ../7006/
效果如下:
將每個目錄下的配置檔案裡面,所有的7001,改成和目錄一樣的數字(替換所有配置檔案中的7001),要替換三個位置。
啟動 redis 服務
[root@localhost conf]# pwd
/opt/app/redis/cluster/redis-6.2.3/conf
[root@localhost conf]# ../bin/redis-server 7001/redis.conf
[root@localhost conf]# ../bin/redis-server 7002/redis.conf
[root@localhost conf]# ../bin/redis-server 7003/redis.conf
[root@localhost conf]# ../bin/redis-server 7004/redis.conf
[root@localhost conf]# ../bin/redis-server 7005/redis.conf
[root@localhost conf]# ../bin/redis-server 7006/redis.conf
建立叢集
使用 redis-cli --cluster 搭建叢集,注意下面的IP,建議使用具體的IP,不要使用127.0.0.1,防止有坑
[root@localhost redis-6.2.3]# pwd
/opt/app/redis/cluster/redis-6.2.3
[root@localhost redis-6.2.3]# ./bin/redis-cli --cluster create 192.168.3.100:7001 192.168.3.100:7002 192.168.3.100:7003 192.168.3.100:7004 192.168.3.100:7005 192.168.3.100:7006 --cluster-replicas 1
測試叢集
至此,叢集就搭建好了,可以測試一下,連線叢集,注意下面的命令,一定要帶上 -c ,表示以叢集的模式訪問:
[root@localhost redis-6.2.3]# ./bin/redis-cli -c -p 7001
如果叢集中,其中一個節點掛掉,從節點會自動變為主節點,若原主節點重連,會自動變為從節點
關閉叢集辦法:
[root@localhost bin]# pwd
/opt/app/redis/cluster/redis-6.2.3/bin
[root@localhost bin]# ./redis-cli -c -p 7001 shutdown
[root@localhost bin]# ./redis-cli -c -p 7002 shutdown
[root@localhost bin]# ./redis-cli -c -p 7003 shutdown
[root@localhost bin]# ./redis-cli -c -p 7004 shutdown
[root@localhost bin]# ./redis-cli -c -p 7005 shutdown
[root@localhost bin]# ./redis-cli -c -p 7006 shutdown
# 如果需要刪除叢集資料,看清楚當前位置
[root@localhost 7001]# pwd
/opt/app/redis/cluster/redis-6.2.3/conf/7001
[root@localhost 7001]# rm -rf appendonly.aof dump.rdb log.log nodes.conf
[root@localhost 7001]# cd ../7002/ ; rm -rf appendonly.aof dump.rdb log.log nodes.conf
[root@localhost 7002]# cd ../7003/ ; rm -rf appendonly.aof dump.rdb log.log nodes.conf
[root@localhost 7003]# cd ../7004/ ; rm -rf appendonly.aof dump.rdb log.log nodes.conf
[root@localhost 7004]# cd ../7005/ ; rm -rf appendonly.aof dump.rdb log.log nodes.conf
[root@localhost 7005]# cd ../7006/ ; rm -rf appendonly.aof dump.rdb log.log nodes.conf
PS:一開始,我用redis-trib.rb搭建叢集,但報出警告說,redis-trib.rb已經不可用了,讓使用redis-cli --cluster代替,下圖的示例後面的命令,是已經幫助我替換好的命令
使用 cluster-create 建立叢集
建議這塊只做瞭解,實踐中,使用上一種建立方式,其實這塊建立叢集,使用的仍然是redis-cli --cluster建立
指令碼位置
在redis的/redis-6.2.3/utils/create-cluster目錄下,有一個create-cluster指令碼,可以使用此指令碼建立叢集
指令碼配置
先編輯一下這個指令碼,開啟之後,可能需要修改前面幾行配置
注意:叢集節點的數量,必須大於6個,否則啟動叢集,會有如下錯誤:
啟動叢集
啟動redis服務,建立叢集
[root@localhost create-cluster]# ./create-cluster start
Starting 30001
Starting 30002
Starting 30003
Starting 30004
Starting 30005
Starting 30006
[root@localhost create-cluster]# ./create-cluster create
啟動之後,會在create-cluster指令碼的位置,自動生成配置檔案、資料檔案、log檔案等
測試叢集
仍然使用 redis-cli -c
[root@localhost redis-6.2.3]# ./bin/redis-cli -c -p 30001
至此,叢集搭建結束。
叢集擴容
叢集擴容時,先增加主節點,再給新增的主節點分配槽,然後增加從節點
在第一種叢集的基礎上,再增加兩個節點,7007和7008,7007作為新增的主節點,7008作為7007的從節點。
新增配置
把7001的配置檔案,複製給7007和7008,並把配置檔案裡面的7001,全部替換成7007和7008。
[root@localhost conf]# pwd
/opt/app/redis/cluster/redis-6.2.3/conf
[root@localhost conf]# mkdir 7007 7008
[root@localhost conf]# cp 7001/redis.conf 7007/redis.conf
[root@localhost conf]# cp 7001/redis.conf 7008/redis.conf
[root@localhost conf]# ll
總用量 0
drwxr-xr-x. 2 root root 112 3月 27 12:01 7001
drwxr-xr-x. 2 root root 112 3月 27 12:01 7002
drwxr-xr-x. 2 root root 112 3月 27 12:01 7003
drwxr-xr-x. 2 root root 112 3月 27 12:01 7004
drwxr-xr-x. 2 root root 112 3月 27 12:01 7005
drwxr-xr-x. 2 root root 112 3月 27 12:01 7006
drwxr-xr-x. 2 root root 24 3月 27 12:05 7007
drwxr-xr-x. 2 root root 24 3月 27 12:05 7008
增加主節點
擴容時,先增加主節點,再增加從節點
先啟動7007節點
[root@localhost redis-6.2.3]# pwd
/opt/app/redis/cluster/redis-6.2.3
[root@localhost redis-6.2.3]# ./bin/redis-server conf/7007/redis.conf
增加主節點之前的叢集狀態
向叢集中增加主節點
[root@localhost redis-6.2.3]# ./bin/redis-cli --cluster add-node 192.168.3.100:7007 192.168.3.100:7001
檢視叢集狀態
新增的節點,已成為叢集中的主節點,但還沒有給新主節點分配槽,0~16383(共16384個)這個範圍的槽,全部被分配在了原來的三個主節點上,即使現在向叢集中set資料,資料仍會被分配到原來的三個主節點上。
分配槽(slot)
現在,為新增的主節點分配槽,執行以下命令:
[root@localhost redis-6.2.3]# ./bin/redis-cli --cluster reshard 192.168.3.100:7001
此時會詢問給新增master節點分配多少個槽,總共16384個,平均分配給4個主節點,每個節點分配4096,就輸入4096
然後詢問接收節點的ID,輸入新增的master節點的ID
然後輸入從哪幾個節點來分,輸入前三個主節點的ID,最後輸入done表示結束。
輸入yes開始資料遷移,等待結束
檢查
使用redis-cli --cluster check檢查當前的叢集狀態,看槽是否已經分配完成
[root@localhost redis-6.2.3]# ./bin/redis-cli --cluster check 192.168.3.100:7001
測試
檢視下面的資料所在的槽和所屬的redis服務埠
至此,叢集增加主節點結束。
增加從節點
增加從節點有兩個步驟:1、將新增節點7008加入到叢集中,暫時作為主節點。2、將新增的節點7008掛接到從節點7007上去。
啟動新增的從節點
[root@localhost redis-6.2.3]# pwd
/opt/app/redis/cluster/redis-6.2.3
[root@localhost redis-6.2.3]# ./bin/redis-server conf/7008/redis.conf
將節點加入到叢集
將新增的節點7008,加入到叢集中,暫時作為主節點
[root@localhost redis-6.2.3]# pwd
/opt/app/redis/cluster/redis-6.2.3
[root@localhost redis-6.2.3]# ./bin/redis-cli --cluster add-node 192.168.3.100:7008 192.168.3.100:7001
掛接節點
將新節點7008,掛接到叢集的7007主節點上,作為其從節點。在7008的客戶端裡面執行以下命令,最後面的ID是主節點7007的ID:
127.0.0.1:7008> cluster replicate 1d708c5042d53b6bc1e855ea41755782b6692e1a
檢視狀態、測試
此時檢視狀態,7008已經成為7007的從節點,而且7008上的資料,和7007上的資料完全一樣
至此,叢集擴容已完成。
叢集縮容
縮容的步驟,正好與擴容相反,先刪除從節點,再將主節點的槽,分配給其他三個主節點的其中一個,然後刪除主節點
刪除從節點
以刪除7008從節點為例,使用redis-cli --cluster del-node命令刪除從節點,192.168.3.100:7001 表示要從哪個叢集刪除(注意這並不是要刪除的節點IP和埠),後面的cd26feeb271c1260ec134d85dcdeaf4c72bfc3ad才表示要刪除的節點ID,也就是7008的ID
[root@localhost redis-6.2.3]# ./bin/redis-cli --cluster del-node 192.168.3.100:7001 cd26feeb271c1260ec134d85dcdeaf4c72bfc3ad
>>> Removing node cd26feeb271c1260ec134d85dcdeaf4c72bfc3ad from cluster 192.168.3.100:7001
>>> Sending CLUSTER FORGET messages to the cluster...
>>> Sending CLUSTER RESET SOFT to the deleted node.
此時再檢視叢集狀態,叢集中已經沒有7008節點了,但是7008的服務還啟動著,現在就可以關掉了
關掉7008服務
將要刪除的主節點的槽分配給其他主節點
在刪除叢集中的主節點7007之前,需要先將其槽分給其他的三個主節點中的某一個,這裡以分配給7001節點為例:
刪除主節點
此時,7007上已經沒有資料和槽了,可以從叢集中刪除7007節點了,刪除方式和刪除從節點一樣,直接執行刪除命令:
[root@localhost redis-6.2.3]# pwd
/opt/app/redis/cluster/redis-6.2.3
[root@localhost redis-6.2.3]# ./bin/redis-cli --cluster del-node 192.168.3.100:7001 1d708c5042d53b6bc1e855ea41755782b6692e1a
>>> Removing node 1d708c5042d53b6bc1e855ea41755782b6692e1a from cluster 192.168.3.100:7001
>>> Sending CLUSTER FORGET messages to the cluster...
>>> Sending CLUSTER RESET SOFT to the deleted node.
[root@localhost redis-6.2.3]#
再檢視叢集狀態,叢集中已經沒有7007節點了
再關閉7007服務即可:
至此,redis叢集縮容完成
Java連線cluster叢集
使用Jedis連線Redis
新建一個簡單的maven專案,在pom檔案中引入jedis依賴:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.1.1</version>
</dependency>
測試:
public class RedisClusterTest {
public static void main(String[] args) {
Set<HostAndPort> nodes = new HashSet();
//叢集的所有節點
nodes.add(new HostAndPort("192.168.3.100", 7001));
nodes.add(new HostAndPort("192.168.3.100", 7002));
nodes.add(new HostAndPort("192.168.3.100", 7003));
nodes.add(new HostAndPort("192.168.3.100", 7004));
nodes.add(new HostAndPort("192.168.3.100", 7005));
nodes.add(new HostAndPort("192.168.3.100", 7006));
//JedisCluster客戶端
JedisCluster jedisCluster = new JedisCluster(nodes);
//set值
jedisCluster.set("a", "a");
jedisCluster.set("b", "b");
jedisCluster.set("c", "c");
jedisCluster.set("d", "d");
//get值
System.out.println(jedisCluster.get("a"));
System.out.println(jedisCluster.get("b"));
System.out.println(jedisCluster.get("c"));
System.out.println(jedisCluster.get("d"));
//關閉jedisCluster
jedisCluster.close();
}
}
SpringBoot專案連線Redis
加入依賴
新建一個SpringBoot專案,在專案中引入以下依賴:
<!-- Spring web的依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringBoot專案pom檔案中,加入redis依賴-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.6.4</version>
</dependency>
<!-- test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<version>2.6.5</version>
<scope>compile</scope>
</dependency>
<!-- test -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<!-- fastjson,設定序列化-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.79</version>
</dependency>
配置叢集IP和埠
在application.properties配置檔案中,加入叢集的節點的配置資訊(這裡做了簡化)
spring.redis.cluster.nodes=192.168.3.100:7001,192.168.3.100:7002,192.168.3.100:7003,192.168.3.100:7004,192.168.3.100:7005,192.168.3.100:7006
配置RedisTemplate的序列化:
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(redisConnectionFactory);
Jackson2JsonRedisSerializer<Object> jsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
redisTemplate.setKeySerializer(stringRedisSerializer);
redisTemplate.setValueSerializer(jsonRedisSerializer);
redisTemplate.setHashKeySerializer(stringRedisSerializer);
redisTemplate.setHashValueSerializer(jsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
測試
@SpringBootTest(classes = RedisBootApplication.class)
public class TestRedisClusterClient {
@Autowired
RedisTemplate<String, Object> redisTemplate;
@Test
public void test1() {
redisTemplate.opsForValue().set("a", 1);
redisTemplate.opsForValue().set("b", 2);
redisTemplate.opsForValue().set("c", 3);
redisTemplate.opsForValue().set("d", 4);
System.out.println(redisTemplate.opsForValue().get("a"));
System.out.println(redisTemplate.opsForValue().get("b"));
System.out.println(redisTemplate.opsForValue().get("c"));
System.out.println(redisTemplate.opsForValue().get("d"));
}
}
在redis-cli中檢視
127.0.0.1:7001> get a
-> Redirected to slot [15495] located at 192.168.3.100:7003
"1"
192.168.3.100:7003> get b
-> Redirected to slot [3300] located at 192.168.3.100:7001
"2"
192.168.3.100:7001> get c
-> Redirected to slot [7365] located at 192.168.3.100:7002
"3"
192.168.3.100:7003> get d
-> Redirected to slot [11298] located at 192.168.3.100:7001
"4"