當前位置:
首頁 > 知識 > redis單點、主從、哨兵sentinel,集群cluster配置使用

redis單點、主從、哨兵sentinel,集群cluster配置使用

  • redis單點、redis主從、redis哨兵 sentinel,redis集群cluster配置搭建與使用
  • 1 .redis 安裝及配置
  • 1.1 redis 單點
  • 1.1.2 在命令窗口操作redis
  • 1.1.3 使用jedis客戶端操作redis
  • 1.1.4 使用spring-redis操作
  • 1.2 redis 主從
  • 1.3 哨兵sentinel
  • 1.3.2 哨兵sentinel配置
  • 1.3.3 啟動哨兵,使用jedis連接哨兵操作redis
  • 1.3.4 編寫程序&運行
  • 1.3.5模擬主節點宕機情況
  • 1.4 redis cluster
  • 1.4.1 配置 redis cluster 集群
  • 1.4.2啟動redis集群
  • 1.4.3 使用jedis連接redis cluster 集群
  • 總結

redis單點、redis主從、redis哨兵 sentinel,redis集群cluster配置搭建與使用

redis是如今被互聯網公司使用最廣泛的一個中間件,我們打開GitHub搜索redis,邊可以看到,該項目的介紹是這樣的:

Redis is an in-memory database that persists on disk. The data model is key-value, but many different kind of values are supported: Strings, Lists, Sets, Sorted Sets, Hashes, HyperLogLogs, Bitmaps.

從這句話中,我們可以提取其特性的關鍵字:

  • in-memory database ,內存資料庫
  • support:Strings , lists, sets ,hashes ,hyperloglogs, bitmaps

也就是高性能,支持數據類型多。本文假設你已經了解redis的基本使用,進而討論redis的單點,高可用,集群。

1 .redis 安裝及配置

redis的安裝十分簡單,打開redis的官網 http://redis.io 。

  1. 下載一個最新版本的安裝包,如 redis-version.tar.gz
  2. 解壓 tar zxvf redis-version.tar.gz
  3. 執行 make (執行此命令可能會報錯,例如確實gcc,一個個解決即可)

如果是 mac 電腦,安裝redis將十分簡單執行brew install redis即可。

安裝好redis之後,我們先不慌使用,先進行一些配置。打開redis.conf文件,我們主要關注以下配置:

port 6379 # 指定埠為 6379,也可自行修改
daemonize yes # 指定後台運行

1.1 redis 單點

安裝好redis之後,我們來運行一下。啟動redis的命令為 :

redishome/bin/redis-server path/to/redis.config

假設我們沒有配置後台運行(即:daemonize no),那麼我們會看到如下啟動日誌:

93825:C 20 Jan 2019 11:43:22.640 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
93825:C 20 Jan 2019 11:43:22.640 # Redis version=5.0.3, bits=64, commit=00000000, modified=0, pid=93825, just started
93825:C 20 Jan 2019 11:43:22.640 # Configuration loaded
93825:S 20 Jan 2019 11:43:22.641 * Increased maximum number of open files to 10032 (it was originally set to 256).
_._
_.-``__ ""-._
_.-`` `. `_. ""-._ Redis 5.0.3 (00000000/0) 64 bit
.-`` .-```. ```/ _.,_ ""-._
( " , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|"` _.-"| Port: 6380
| `-._ `._ / _.-" | PID: 93825
`-._ `-._ `-./ _.-" _.-"
|`-._`-._ `-.__.-" _.-"_.-"|
| `-._`-._ _.-"_.-" | http://redis.io
`-._ `-._`-.__.-"_.-" _.-"
|`-._`-._ `-.__.-" _.-"_.-"|
| `-._`-._ _.-"_.-" |
`-._ `-._`-.__.-"_.-" _.-"
`-._ `-.__.-" _.-"
`-._ _.-"
`-.__.-"

無論是否配置了後台運行,啟動成功之後,我們可以新開一個命令行窗口來操作試試。

1.1.2 在命令窗口操作redis

使用命令:telnet localhost 6379 來連接redis,或者你可以直接使用代碼來連接測試。連接之後,看到如下信息:

Connected to localhost.
Escape character is "^]".

我們輸入幾個命令試試:

set hello world 設置key-value
get hello 獲取key值
expire hello 10 設置10秒過期
ttl hello 查看過期時間
del hello 刪除key

如此,我們便體驗了一把redis,可以說是非常簡單了。剛才我們是使用命令行來操作redis的,下面我們來使用代碼操作一下redis,以Java為例,我們使用一個開源的 java - redis客戶端。

1.1.3 使用jedis客戶端操作redis

打開GitHub,搜索redis,進入到項目主頁之後,我們可以看到使用方法:

  1. 加入jedis依賴

<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.0.0</version>
<type>jar</type>
<scope>compile</scope>
</dependency>

  1. 編寫代碼如下

Jedis jedis = new Jedis("localhost",6379);
jedis.set("hello", "world");
String value = jedis.get("hello");
System.out.println(value); // get world
jedis.del("hello");
System.out.println(jedis.get("hello"));// get null

1.1.4 使用spring-redis操作

上面jedis操作redis的例子很簡單,除了使用jedis之外,還可以使用spring-redis。步驟如下

  1. 配置redis

<bean id="jedisConnFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:use-pool="true"/>
<!-- redis template definition -->
<bean id="redisTemplate"
class="org.springframework.data.redis.core.RedisTemplate"
p:connection-factory-ref="jedisConnFactory"/>

  1. 編寫代碼

public class Example {
// inject the actual template
@Autowired
private RedisTemplate<String, String> template;
// inject the template as ListOperations
// can also inject as Value, Set, ZSet, and HashOperations
@Resource(name="redisTemplate")
private ListOperations<String, String> listOps;
public void addLink(String userId, URL url) {
listOps.leftPush(userId, url.toExternalForm());
// or use template directly
redisTemplate.boundListOps(userId).leftPush(url.toExternalForm());
}
}

1.2 redis 主從

上面我們啟動了一台redis,並對其進行操作。當然這只是實驗性的玩玩。假設我們生產環境使用了一台redis,redis掛了怎麼辦?如果等到運維重啟redis,並恢復好數據,可能需要花費很長時間。那麼在這期間,我們的服務是不可用的,這應該是不能容忍的。假設我們做了主從,主庫掛了之後,運維讓從庫接管,那麼服務可以繼續運行,正所謂有備無患。

redis主從配置非常簡單,過程如下(ps 演示情況下主從配置在一台電腦上):

  1. 複製兩個redis配置文件(啟動兩個redis,只需要一份redis程序,兩個不同的redis配置文件即可)

mkdir redis-master-slave
cp path/to/redis/conf/redis.conf path/to/redis-master-slave master.conf
cp path/to/redis/conf/redis.conf path/to/redis-master-slave slave.conf

  1. 修改配置

## master.conf
port 6379
## master.conf
port 6380
slaveof 127.0.0.1 6379

  1. 分別啟動兩個redis

redis-server path/to/redis-master-slave/master.conf
redis-server path/to/redis-master-slave/slave.conf

啟動之後,打開兩個命令行窗口,分別執行telnet localhost 6379 telnet localhost 6380

然後分別在兩個窗口中執行 info 命令,可以看到

# Replication
role:master
# Replication
role:slave
master_host:127.0.0.1
master_port:6379

主從配置沒問題。

然後在master 窗口執行 set 之後,到slave窗口執行get,可以get到,說明主從同步成功。

這時,我們如果在slave窗口執行 set ,會報錯:

-READONLY You can"t write against a read only replica.

因為從節點是只讀的。

1.3 哨兵sentinel

上面我們介紹了主從,從庫作為一個「傀儡」,可以在需要的時候「頂上來」,」接盤「。我們配置的主從是為了」有備無患「,在主redis掛了之後,可以立馬切換到從redis上,可能只需要花幾分鐘的時間,但是仍然是需要人為操作。假設主redis在晚上23點掛了,10分鐘之後你接到電話,老闆讓你趕緊修復,於是你從被窩爬起來整,豈不是很頭疼。假如你關機了,又其他人知道伺服器密碼,那系統豈不是要停機一晚上?太可怕了。

這個時候redis sentinel 就派上用場了。sentinel 通常翻譯成哨兵,就是放哨的,這裡它就是用來監控主從節點的健康情況。客戶端連接redis主從的時候,先連接 sentinel,sentinel會告訴客戶端主redis的地址是多少,然後客戶端連接上redis並進行後續的操作。當主節點掛掉的時候,客戶端就得不到連接了因而報錯了,客戶端重新想sentinel詢問主master的地址,然後客戶端得到了[新選舉出來的主redis],然後又可以愉快的操作了。

1.3.2 哨兵sentinel配置

為了說明sentinel的用處,我們做個試驗。配置3個redis(1主2從),1個哨兵。步驟如下:

mkdir redis-sentinel
cd redis-sentinel
cp redis/path/conf/redis.conf path/to/redis-sentinel/redis01.conf
cp redis/path/conf/redis.conf path/to/redis-sentinel/redis02.conf
cp redis/path/conf/redis.conf path/to/redis-sentinel/redis03.conf
touch sentinel.conf

上我們創建了 3個redis配置文件,1個哨兵配置文件。我們將 redis01設置為master,將redis02,redis03設置為slave。

vim redis01.conf
port 63791
vim redis02.conf
port 63792
slaveof 127.0.0.1 63791
vim redis03.conf
port 63793
slaveof 127.0.0.1 63791
vim sentinel.conf
daemonize yes
port 26379
sentinel monitor mymaster 127.0.0.1 63793 1 # 下面解釋含義

上面的主從配置都熟悉,只有哨兵配置 sentinel.conf,需要解釋一下:

mymaster 為主節點名字,可以隨便取,後面程序裡邊連接的時候要用到
127.0.0.1 63793 為主節點的 ip,port
1 後面的數字 1 表示選舉主節點的時候,投票數。1表示有一個sentinel同意即可升級為master

1.3.3 啟動哨兵,使用jedis連接哨兵操作redis

上面我們配置好了redis主從,1主2從,以及1個哨兵。下面我們分別啟動redis,並啟動哨兵

redis-server path/to/redis-sentinel/redis01.conf
redis-server path/to/redis-sentinel/redis02.conf
redis-server path/to/redis-sentinel/redis03.conf
redis-server path/to/redis-sentinel/sentinel.conf --sentinel

啟動之後,可以分別連接到 3個redis上,執行info查看主從信息。

1.3.4 編寫程序&運行

下面使用程序來連接哨兵,並操作redis。

public static void main(String[] args) throws Exception{
Set<String> hosts = new HashSet<>();
hosts.add("127.0.0.1:26379");
//hosts.add("127.0.0.1:36379"); 配置多個哨兵

JedisSentinelPool pool = new JedisSentinelPool("mymaster",hosts);
Jedis jedis = null;
for(int i=0 ;i<20;i++){
Thread.sleep(2000);
try{
jedis = pool.getResource();
String v = randomString();
jedis.set("hello",v);
System.out.println(v+"-->"+jedis.get("hello").equals(v));
}catch (Exception e){
System.out.println(" [ exception happened]" + e);
}
}
}

程序非常簡單,循環運行20次,連接哨兵,將隨機字元串 set到redis,get結果。列印信息,異常捕獲。

1.3.5模擬主節點宕機情況

運行上面的程序(注意,在實驗這個效果的時候,可以將sleep時間加長或者for循環增多,以防程序提前停止,不便看整體效果),然後將主redis關掉,模擬redis掛掉的情況。現在主redis為redis01,埠為63791

redis-cli -p 63791 shutdown

這個時候如果sentinel沒有設置後台運行,可以在命令行窗口看到 master切換的情況日誌。

# Sentinel ID is fd0634dc9876ec60da65db5ff1e50ebbeefdf5ce
# +monitor master mymaster 127.0.0.1 63791 quorum 1
* +slave slave 127.0.0.1:63792 127.0.0.1 63792 @ mymaster 127.0.0.1 63791
* +slave slave 127.0.0.1:63793 127.0.0.1 63793 @ mymaster 127.0.0.1 63791
# +sdown master mymaster 127.0.0.1 63791
# +odown master mymaster 127.0.0.1 63791 #quorum 1/1
# +new-epoch 1
# +try-failover master mymaster 127.0.0.1 63791
# +vote-for-leader fd0634dc9876ec60da65db5ff1e50ebbeefdf5ce 1
# +elected-leader master mymaster 127.0.0.1 63791
# +failover-state-select-slave master mymaster 127.0.0.1 63791
# +selected-slave slave 127.0.0.1:63793 127.0.0.1 63793 @ mymaster 127.0.0.1 63791
* +failover-state-send-slaveof-noone slave 127.0.0.1:63793 127.0.0.1 63793 @ mymaster 127.0.0.1 63791
* +failover-state-wait-promotion slave 127.0.0.1:63793 127.0.0.1 63793 @ mymaster 127.0.0.1 63791
# +promoted-slave slave 127.0.0.1:63793 127.0.0.1 63793 @ mymaster 127.0.0.1 63791
# +failover-state-reconf-slaves master mymaster 127.0.0.1 63791
* +slave-reconf-sent slave 127.0.0.1:63792 127.0.0.1 63792 @ mymaster 127.0.0.1 63791
* +slave-reconf-inprog slave 127.0.0.1:63792 127.0.0.1 63792 @ mymaster 127.0.0.1 63791
* +slave-reconf-done slave 127.0.0.1:63792 127.0.0.1 63792 @ mymaster 127.0.0.1 63791
# +failover-end master mymaster 127.0.0.1 63791
# +switch-master mymaster 127.0.0.1 63791 127.0.0.1 63793
* +slave slave 127.0.0.1:63792 127.0.0.1 63792 @ mymaster 127.0.0.1 63793
* +slave slave 127.0.0.1:63791 127.0.0.1 63791 @ mymaster 127.0.0.1 63793
# +sdown slave 127.0.0.1:63791 127.0.0.1 63791 @ mymaster 127.0.0.1 63793
# -sdown slave 127.0.0.1:63791 127.0.0.1 63791 @ mymaster 127.0.0.1 63793
* +convert-to-slave slave 127.0.0.1:63791 127.0.0.1 63791 @ mymaster 127.0.0.1 63793

上面的日誌較多,仔細找找可以看到下面幾行主要的:

初始情況下,1主2從
# +monitor master mymaster 127.0.0.1 63791 quorum 1
* +slave slave 127.0.0.1:63792 127.0.0.1 63792 @ mymaster 127.0.0.1 63791
* +slave slave 127.0.0.1:63793 127.0.0.1 63793 @ mymaster 127.0.0.1 63791
發現主掛了,準備 故障轉移
# +try-failover master mymaster 127.0.0.1 63791
將主切換到了 63793 即redis03
# +switch-master mymaster 127.0.0.1 63791 127.0.0.1 63793

這個日誌比較晦澀,從代碼運行效果看,如下:

14:45:20.675 [main] INFO redis.clients.jedis.JedisSentinelPool - Trying to find master from available Sentinels...
14:45:25.731 [main] DEBUG redis.clients.jedis.JedisSentinelPool - Connecting to Sentinel 192.168.1.106:26379
14:45:25.770 [main] DEBUG redis.clients.jedis.JedisSentinelPool - Found Redis master at 127.0.0.1:63792
14:45:25.771 [main] INFO redis.clients.jedis.JedisSentinelPool - Redis master running at 127.0.0.1:63792, starting Sentinel listeners...
14:45:25.871 [main] INFO redis.clients.jedis.JedisSentinelPool - Created JedisPool to master at 127.0.0.1:63792
ejahaeegig-->true
deeeadejjf-->true
[ exception happened]redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
[ exception happened]........
[ exception happened]........
[ exception happened]........
[ exception happened]........
[ exception happened]........
[ exception happened]........
[ exception happened]........
[ exception happened]........
[ exception happened]........
14:46:02.737 [MasterListener-mymaster-[192.168.1.106:26379]] DEBUG redis.clients.jedis.JedisSentinelPool - Sentinel 192.168.1.106:26379 published: mymaster 127.0.0.1 63792 127.0.0.1 63793.
14:46:02.738 [MasterListener-mymaster-[192.168.1.106:26379]] INFO redis.clients.jedis.JedisSentinelPool - Created JedisPool to master at 127.0.0.1:63793
haiihiihbb-->true
ifgebdcicd-->true
aajhbjagag-->true
Process finished with exit code 0

從結果看出

  1. 開始正常操作redis,並設置了兩次。
  2. 主redis掛了,jedis得不到連接,報錯了JedisConnectionException:Could not get a resource from the pool
  3. 主redis沒選好之前,程序持續報錯。
  4. 主redis選好了,程序正常運行,最後結束。

我們看到最後一次運行設置的值是aajhbjagag,我們可以連接剩下的2台redis中的任意一台,get hello,結果肯定是一致的。

1.4 redis cluster

上面的章節中,我們分別學習了redis 單點,redis主從,並增加了高可用的 sentinel 哨兵模式。我們所做的這些工作只是保證了數據備份以及高可用,目前為止我們的程序一直都是向1台redis寫數據,其他的redis只是備份而已。實際場景中,單個redis節點可能不滿足要求,因為:

  • 單個redis並發有限
  • 單個redis接收所有的數據,最終回導致內存太大,內存太大回導致rdb文件過大,從很大的rdb文件中同步恢複數據會很慢。

所有,我們需要redis cluster 即redis集群。

Redis 集群是一個提供在多個Redis間節點間共享數據的程序集。

Redis集群並不支持處理多個keys的命令,因為這需要在不同的節點間移動數據,從而達不到像Redis那樣的性能,在高負載的情況下可能會導致不可預料的錯誤.

Redis 集群通過分區來提供一定程度的可用性,在實際環境中當某個節點宕機或者不可達的情況下繼續處理命令. Redis 集群的優勢:

  • 自動分割數據到不同的節點上。
  • 整個集群的部分節點失敗或者不可達的情況下能夠繼續處理命令。

為了配置一個redis cluster,我們需要準備至少6台redis,為啥至少6台呢?我們可以在redis的官方文檔中找到如下一句話:

Note that the minimal cluster that works as expected requires to contain at least three master nodes.

因為最小的redis集群,需要至少3個主節點,既然有3個主節點,而一個主節點搭配至少一個從節點,因此至少得6台redis。然而對我來說,就是複製6個redis配置文件。本實驗的redis集群搭建依然在一台電腦上模擬。

1.4.1 配置 redis cluster 集群

上面提到,配置redis集群需要至少6個redis節點。因此我們需要準備及配置的節點如下:

主:redis01 從 redis02 slaveof redis01
主:redis03 從 redis04 slaveof redis03
主:redis05 從 redis06 slaveof redis05
mkdir redis-cluster
cd redis-cluster
mkdir redis01 到 redis06 6個文件夾
cp redis.conf 到 redis01 ... redis06
修改埠
分別配置3組主從關係

1.4.2啟動redis集群

上面的配置完成之後,分別啟動6個redis實例。配置正確的情況下,都可以啟動成功。然後運行如下命令創建集群:

redis-5.0.3/src/redis-cli --cluster create 127.0.0.1:6371 127.0.0.1:6372 127.0.0.1:6373 127.0.0.1:6374 127.0.0.1:6375 127.0.0.1:6376 --cluster-replicas 1

注意,這裡使用的是ip:port,而不是 domain:port ,因為我在使用 localhost:6371 之類的寫法執行的時候碰到錯誤:

ERR Invalid node address specified: localhost:6371

執行成功之後,連接一台redis,執行 cluster info 會看到類似如下信息:

cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:3
cluster_current_epoch:6
cluster_my_epoch:1
cluster_stats_messages_ping_sent:1515
cluster_stats_messages_pong_sent:1506
cluster_stats_messages_sent:3021
cluster_stats_messages_ping_received:1501
cluster_stats_messages_pong_received:1515
cluster_stats_messages_meet_received:5
cluster_stats_messages_received:3021

我們可以看到cluster_state:ok,cluster_slots_ok:16384,cluster_size:3。

1.4.3 使用jedis連接redis cluster 集群

上面我們配置了一個redis集群,包含6個redis節點,3主3從。下面我們來使用jedis來連接redis集群。代碼如下:

public static void main(String[] args) {
Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
//Jedis Cluster will attempt to discover cluster nodes automatically
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 6371));
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 6372));
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 6373));
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 6374));
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 6375));
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 6376));
JedisCluster jc = new JedisCluster(jedisClusterNodes);
jc.set("foo", "bar");
String value = jc.get("foo");
System.out.println(" ===> " + value);
}

上面我們設置了信息set foo bar,但是不知道被設置到那一台redis上去了。請讀者思考一下,我們是集群模式,所以數據被分散放到不同的槽中了,Redis 集群有16384個哈希槽,每個key通過CRC16校驗後對16384取模來決定放置哪個槽.集群的每個節點負責一部分hash槽,舉個例子,比如當前集群有3個節點,那麼:

  • 節點 A 包含 0 到 5500號哈希槽.
  • 節點 B 包含5501 到 11000 號哈希槽.
  • 節點 C 包含11001 到 16384號哈希槽.

看到這裡你應該還是不知道set foo bar 放到哪台redis上去了,不妨嘗試連接任意一台redis探索一下,你會知道的。

總結

至此,我們了解並動手實踐了redis的安裝,redis單點,redis主從,redis 哨兵 sentinel,redis 集群cluster。一切動手做了才會熟悉。

Lua腳本在redis分散式鎖場景的運用

Netty開發redis客戶端,Netty發送redis命令,netty解析redis消息

作者:逃離沙漠

原文:https://www.cnblogs.com/demingblog/p/10295236.html

redis單點、主從、哨兵sentinel,集群cluster配置使用

打開今日頭條,查看更多圖片

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 程序員小新人學習 的精彩文章:

vue項目性能優化(路由懶載入、gzip加速、cdn加速)
瀏覽器緩存機制

TAG:程序員小新人學習 |