redis叢集環境搭建以及java中jedis客戶端叢集程式碼實現
redis相關網站:
作業系統:centos 6.3
redis版本:3.0.6
java客戶端版本: jedis 2.7.2
redis客戶端圖形使用者介面:RedisDesktopManager
1.redis服務端叢集搭建步驟:
1.下載redis安裝包,進行解壓安裝
2.安裝ruby、rubygems install ruby ,安裝ruby的原因是,在進行叢集的時候,使用的是ruby語言工具實現的,所以在叢集之前首先需要搭建ruby的環境
3.在上述步驟完成之後,便可以搭建叢集環境,redis提供了兩種叢集搭建方法,執行指令碼方法(安裝包下面的util包中)和手動搭建。
注意:
1.在叢集的時候,如果是遠端客戶端訪問redis服務端,那麼在分片的時候,需要使用Ip進行分片,下面會詳細說
2.在建立每個節點的時候,不要只用redis-server ,使用絕對路徑下的redis-server xxx
附件:在安裝ruby的時候,需要gemredis,下載地址在下面。
2.客戶端(java):
注意:
1.本文的客戶端使用的是java,官網中對於java客戶端也提供了不少的client,但是本文使用的是官方推薦的jedis。
2.在專案開發中,一般情況下都會用到spring來管理應用,本文也是如此,spring 本身也提供了對redis的整合支援,具體的網址:http://projects.spring.io/spring-data-redis,
但是好像目前spring-data-redis不提供叢集的功能,所以本文沒有使用它,而是使用了原裝的jedis來進行開發,如果在專案中沒有用到叢集的功能,則可以使用spirng-data-redis。
下面是具體的程式碼實現
1.maven依賴
Java程式碼- <dependency>
- <groupId>redis.clients</groupId>
- <artifactId>jedis</artifactId>
-
<version>2.7.2</version>
- </dependency>
2.applicationContext.xml中的配置
Java程式碼- <!-- jedis cluster config -->
- <bean name="genericObjectPoolConfig" class="org.apache.commons.pool2.impl.GenericObjectPoolConfig" >
- <property name="maxWaitMillis" value="-1" />
- <property name="maxTotal" value="1000" />
- <property name="minIdle" value="8" />
- <property name="maxIdle" value="100" />
- </bean>
- <bean id="jedisCluster" class="com.besttone.subscribe.util.JedisClusterFactory">
- <property name="addressConfig">
- <value>classpath:redis-config.properties</value>
- </property>
- <property name="addressKeyPrefix" value="address" />
- <property name="timeout" value="300000" />
- <property name="maxRedirections" value="6" />
- <property name="genericObjectPoolConfig" ref="genericObjectPoolConfig" />
- </bean>
3.JedisClusterFactory實現類
Java程式碼- public class JedisClusterFactory implements FactoryBean<JedisCluster>, InitializingBean {
- private Resource addressConfig;
- private String addressKeyPrefix ;
- private JedisCluster jedisCluster;
- private Integer timeout;
- private Integer maxRedirections;
- private GenericObjectPoolConfig genericObjectPoolConfig;
- private Pattern p = Pattern.compile("^.+[:]\\d{1,5}\\s*$");
- @Override
- public JedisCluster getObject() throws Exception {
- return jedisCluster;
- }
- @Override
- public Class<? extends JedisCluster> getObjectType() {
- return (this.jedisCluster != null ? this.jedisCluster.getClass() : JedisCluster.class);
- }
- @Override
- public boolean isSingleton() {
- return true;
- }
- private Set<HostAndPort> parseHostAndPort() throws Exception {
- try {
- Properties prop = new Properties();
- prop.load(this.addressConfig.getInputStream());
- Set<HostAndPort> haps = new HashSet<HostAndPort>();
- for (Object key : prop.keySet()) {
- if (!((String) key).startsWith(addressKeyPrefix)) {
- continue;
- }
- String val = (String) prop.get(key);
- boolean isIpPort = p.matcher(val).matches();
- if (!isIpPort) {
- throw new IllegalArgumentException("ip 或 port 不合法");
- }
- String[] ipAndPort = val.split(":");
- HostAndPort hap = new HostAndPort(ipAndPort[0], Integer.parseInt(ipAndPort[1]));
- haps.add(hap);
- }
- return haps;
- } catch (IllegalArgumentException ex) {
- throw ex;
- } catch (Exception ex) {
- throw new Exception("解析 jedis 配置檔案失敗", ex);
- }
- }
- @Override
- public void afterPropertiesSet() throws Exception {
- Set<HostAndPort> haps = this.parseHostAndPort();
- jedisCluster = new JedisCluster(haps, timeout, maxRedirections,genericObjectPoolConfig);
- }
- public void setAddressConfig(Resource addressConfig) {
- this.addressConfig = addressConfig;
- }
- public void setTimeout(int timeout) {
- this.timeout = timeout;
- }
- public void setMaxRedirections(int maxRedirections) {
- this.maxRedirections = maxRedirections;
- }
- public void setAddressKeyPrefix(String addressKeyPrefix) {
- this.addressKeyPrefix = addressKeyPrefix;
- }
- public void setGenericObjectPoolConfig(GenericObjectPoolConfig genericObjectPoolConfig) {
- this.genericObjectPoolConfig = genericObjectPoolConfig;
- }
- }
4.redis-config.properties檔案
這是一個叢集環境,六個節點(不同埠),三個master ,三個slaver
Java程式碼- address1=192.168.30.139:7000
- address2=192.168.30.139:7001
- address3=192.168.30.139:7002
- address4=192.168.30.139:7003
- address5=192.168.30.139:7004
- address6=192.168.30.139:7005
5.專案目錄圖
6.程式碼中使用(此程式碼為從redis中獲取相關資訊)
ok,執行之後,會發現redis會根據不同的key,把它們放入到不同的節點中,如下圖
7.三個master節點中的資料
8.三個slave節點中的資料
實踐過程中碰到的問題:
1.在一切準備好了之後,在操作redis的時候,卻報錯誤:Too many Cluster redirections
由於,我是windows開發環境,在本機開了一個虛擬機器,然後在虛擬機器中搭建的linux叢集環境,本機的ip和虛擬機器中的ip不相同,所以報這個錯誤,
解決方法:在redis叢集搭建過程中,在為每個節點分hash槽的時候,執行如下程式碼(其中,xxx為叢集環境中的ip):
Java程式碼- ./redis-trib.rb create --replicas 1 xxx.xxx.xxx.xxx:7000 xxx.xxx.xxx.xxx:7001 xxx.xxx.xxx.xxx:7002 xxx.xxx.xxx.xxx:7003 xxx.xxx.xxx.xxx:7004 xxx.xxx.xxx.xxx:7005./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
2.在一切搭建好後,我們使用redis-cli登陸,當命令:set msg XXX時,報錯:
Java程式碼- (error) MOVED 6257 192.168.30.141:7001
解決:在使用客戶端登陸時:加上-c引數,即:
Java程式碼- redis-cli -c -h 192.168.30.141 -p 7000
ok,以上滿足使用,結束!!
-----------------------------------------------------------------------下面是我前一段時間看redis資料,總結的一些東東,記錄下來-------------------------------------------------------------------------------------------
1.redis是什麼?
redis(remote dictionary server):是一個以key-value形式儲存於記憶體中的資料庫.提供了 String / List / Set / Sort Set /Hash 五種資料結構。
伺服器在斷電之後,仍然可以恢復到斷電之前的狀態。
資料: 官網 : http://redis.io 中文網: http://www.redis.cn/ 相關文件: http://redisdoc.com/
2.redis特點?
執行緒模型:單執行緒-多路複用io模型
效能高:支援讀 11萬/秒 , 寫 8萬/秒
儲存: 記憶體 ; RDB檔案(二進位制安全的真實資料) ; AOF檔案(客戶端的命令集合)
事務: 支援事務(每個客戶端序列執行命令,其他客戶端處於阻塞狀態)
釋出/訂閱模式: 功能? 什麼場景使用??
3.redis資料型別
String:動態字串(每個key都是一個String)
編碼方式:int / raw() /embstr
應用場景:普通的string場景
List:列表結構,有序可重複的結構。它擁有佇列的特性。
編碼方式:ziplist / linkedlist (如果資料量較小,且是數字或者字串,則內部結構為 ziplist)
應用場景:普通的集合資料
Set:集合結構,不重複的集合結構。
編碼方式:intset(整數集合) / hashtable
應用場景:普通的非重複集合資料;支援取交集、取並集等操作
Sort Set:有序集合結構,和Set比較起來,它是有序的。
編碼方式:ziplist / skiplist
應用場景:有序不重複的集合資料
Hash:雜湊結構,儲存多個key:value的結構,此種結構可以儲存物件 ; 如 HMSET user(key) username value1 password value2
編碼方式:ziplist / hashtable
應用場景: 從關係型資料庫去出一條資料,就可以讓入到此種結構中
4.記憶體優化
redis提供記憶體回收策略,根據使用的情況可以選擇適當的回收策略
redis提供記憶體共享策略,伺服器啟動時,會自動建立0-9999的數字物件,其他地方使用,可以直接引用。
本質:對記憶體的操作,其實是在每一個redis物件結構內都有一個count的屬性,該屬性記錄了這個物件被引用的次數,如果為0,那麼在記憶體回收時將回收該空間。
save引數調整:當滿足條件時,觸發SAVE命令,持久化到RDB檔案
appendonly引數: 預設no ,若yes,則開啟AOF檔案持久化; BGREWRITEAOF 命令 持久化。其中appendsync引數調整具體的持久化策略,預設為每秒
記憶體回收策略:
5.釋出訂閱模式
6.資料過期設定
可以根據業務需求,將某些資料進行日期設定
7.事務
單執行緒處理所有客戶端發來的請求,所以當有一個客戶端在執行,其他客戶端只能處於阻塞態。只有當前客戶端請求完畢,其他客戶端才能請求
8.資料儲存
RDB檔案模式(快照):該模式儲存的是真實資料,SAVE /BGSAVE 命令 可以將記憶體中的資料儲存到磁碟檔案中。SAVE和BGSAVE區別在於,SAVE是同步命令,
即當執行該命令,其他客戶端處於阻塞狀態;而BGSAVE 命令則是開啟一個子程序處理,不會影響主程序操作。
AOF檔案模式:該模式儲存的是伺服器執行的命令集合,BGREWRITEAOF 命令。 該模式是appendonly引數控制,若開啟,則會將資料同步到aof檔案中
特點:該模式下,會在伺服器端開闢一段緩衝記憶體來儲存最近時間單位的命令,所以該點要注意。同樣,它也是子程序進行執行
注意:AOF模式的更新頻率比RDB高,若開啟AOF模式的情況下,優先載入AOF檔案內容
9.資料恢復策略
若RDB模式開啟:重啟伺服器只加載rdb檔案內容
若AOF模式開啟:重啟伺服器只加載aof檔案內容
若兩者都開啟:只加載aof檔案內容
10主從複製
功能:資料備份,讀寫分離(測試環境,主伺服器寫,從伺服器讀)
步驟:在從服務端器執行: slaveof <masterip> <masterport> 即可維持關係;配置檔案中也可以
特點:
1.master可以有多個slave
2.除了多個slave連到相同的master外,slave也可以連線其他slave形成圖狀結構
3.主從複製不會阻塞master。也就是說當一個或多個slave與master進行初次同步資料時,master可以繼續處理client發來的請求。相反slave在初次同步資料時則會阻塞不能處理client的請求。
4.主從複製可以用來提高系統的可伸縮性,我們可以用多個slave 專門用於client的讀請求,比如sort操作可以使用slave來處理。也可以用來做簡單的資料冗餘
5.可以在master禁用資料持久化,只需要註釋掉master 配置檔案中的所有save配置,然後只在slave上配置資料持久化。
6.主伺服器可以關閉持久化功能(註釋掉save引數)
11.sentinel(監測系統)
本質:是一個執行在特殊模式下的redis伺服器。
功能:監控執行在多機上的主redis伺服器,若有某一臺主伺服器出現故障,將自動把其他正常的從伺服器切換為主伺服器,代替出現故障主伺服器的工作。
特點:
1.不發揮資料庫的功能(所有對key以及資料型別操作的命令不能使用)
2.將會給監控的主伺服器以及主伺服器所屬的從伺服器傳送命令,確認是否下線
3.會和監控同一個主伺服器的其他sentinel伺服器通訊,作用是在共同判斷所監控的主伺服器的狀態
4.根據多個sentinel判斷的主伺服器狀態,來決定是否要進行主從切換,故障轉移等
轉移:sentinel監控的主伺服器配置引數要在 sentinel.conf 檔案中配置,啟動時載入
具體配置安裝步驟:
1.http://blog.csdn.net/pi9nc/article/details/17735653
2.http://blog.csdn.net/luyee2010/article/details/9385155
12.叢集
功能:將眾多的key-value集合存在多個節點上,當某一個節點出現障礙,不影響整個叢集的功能。
涉及到的關鍵詞:
節點:一個埠的redis服務便是一個節點
槽指派(叢集將整個系統分為16384個hash槽):這16384個槽位要全部分佈在叢集中的主節點上。
重新分片:若某個主節點故障了,將該主節點的槽位分配到其他可以用的主節點上。
上線/下線狀態: 是否全部的槽位都分佈在節點上。
特點:
1.如果某個節點要叢集,必須要設定cluster-enabled yes
2.每個節點都有這16384個槽位所屬的節點資訊,如果值沒有正確進入槽位,那麼該節點會提示系統將資訊放入正確槽位。重定向的過程會出現一個面向客戶端隱藏的MOVED錯誤
3.叢集線上狀態也可以進行重新分片
4.叢集中的主節點使用者處理客戶端命令,從節點用於複製主節點的資料,主節點下線時,從節點代替主節點的工作
//注意:目前官方提供的叢集功能仍處於內測版本。
13.redis基準
redis自帶的redis-benchmark 工具,支援各種引數進行效能測試
特點:
1.可以模擬多個客戶端處理任意個請求
2.可以測試僅僅少數使用的命令等
注意:測試發現,linux環境下部署的redis伺服器效能遠高於windows下部署的redis伺服器效能, 不在一個層級上面
14.關係資料庫模型的轉換
關係型資料庫表結構:user表 (uid username password birthday )
在redis中可以這樣存在:
1.主鍵: SET user:uid 1 、 GET user:1
2.其他欄位:SET user:uid:username GET user:5:username ( 5 是通過引數值傳進來的)
3.表資料也可以存在hash結構中: HMSET user:uid username value1 password value2 birthday value3
15.排序
16.管道
功能:客戶端一次可以傳送多個命令到伺服器,減少往返時延。大大提高效能。
17.優化
redis提供一些簡單的記憶體優化策略,如過期資料清除,記憶體資料共享,
18.持久化