Redis+Twemproxy+HAProxy集羣(轉) 乾貨

原文地址:Redis+Twemproxy+HAProxy集羣  乾貨

Redis主從模式

Redis數據庫與傳統數據庫屬於並行關係,也就是說傳統的關係型數據庫保存的是結構化數據,而Redis保存的是一些所謂的 臨時 數據,由於Redis具有一項很強的功能 持久化數據 ,發現Redis好像也能夠作一些傳統數據庫的開發。可是如今Redis除了能夠進行數據的存儲以外,實際上也能夠在一些系統的架構設計之中做爲數據的緩衝點: 
若是要想實現主從模式的配置,首先必定要準備出三臺Redis實例,本次爲了方便將在一臺主機上進行模擬,也就是說在這一臺主機上將準備出三個Redis實例,分別對應的端口爲:637九、6380、6381,其中6379運行的Redis服務爲主服務,而其它兩個端口運行的服務爲從服務。css

1.若是要想進行主從的模式匹配,主服務器上不須要作出任何的變化,也就是說主服務器根本就不關心是否有從服務器;java

2.全部的從服務的配置文件redis-6380.conf、redis-6381.conf必需要求明確的設置出它對應的主服務器。linux

  • 編輯redis-6380.conf配置文件:vim /usr/local/redis/conf/redis-6380.conf; 
    配置主服務器的IP地址:slaveof 192.168.125.161 6379 
    設置主服務器的密碼:masterauth mldnjava
  • 隨後redis-6381.conf配置文件採用與之同樣的方式完成處理;

3.啓動全部的Redis數據服務:nginx

/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis-6379.conf /usr/local/redis/bin/redis-server /usr/local/redis/conf/redis-6380.conf /usr/local/redis/bin/redis-server /usr/local/redis/conf/redis-6381.conf

4.登陸6379端口的Redis服務主服務查看全部的副本信息:git

/usr/local/redis/bin/redis-cli -h 192.168.125.161 -p 6379 -a mldnjava info replication
connected_slaves:2 slave0:ip=192.168.125.161,port=6380,state=online,offset=99,lag=0 slave1:ip=192.168.125.161,port=6381,state=online,offset=99,lag=0

若是能夠發現以上的信息就表示如今6379下有兩個從節點。github

5.操做主節點6379的數據:set mldn javaredis

  • 隨後退出此客戶端,隨意登陸6380或6381的主機:get mldn; 
    這個時候必定是經過主節點進行數據的設置,然後自動同步到全部的從節點上,這樣的好處是能夠進行數據的備份處理,若是你如今直接在從節點上操做,則會出現以下錯誤提示: (error) READONLY You can't write against a read only slave. 。

備註: 
主從設計的最大好處在於:能夠自動對數據作備份; 主從設計模式的最大缺點在於:只可以作備份,而出現災難以後沒法當即恢復。算法

Redis哨兵機制

哨兵機制原理

只要是進行高可用的架構部署,那麼就必須保證多節點,在Redis裏面使用了主從模式能夠實現多節點配置,可是傳統的主從模式的設計有一個缺陷:一旦Master主機出現了問題以後,兩臺Slave主機將沒法提供正常的工做支持,例如:slave主機爲只讀主機,並且若是要想繼續提供支持,那麼你至少應該經過剩餘的幾臺slave裏面去推選出一個新的master,而且最爲重要的是,這個新的master還必須可以被用戶的程序找到。 
主從模式
哨兵機制(Sentinel) 
Redis哨兵是redis官方推薦的redis高可用(HA)解決方案之一;spring

sentinel的功能: 
監控(Monitoring),sentinel時刻監控着redis master-slave 是否正常運行; 
通知(Notification),sentinel 能夠經過api來通知管理員,被監控的 redis master-slave 出現了問題; 
自動故障轉移(Automatic failover),當redis master出現故障不可用狀態,sentinel 會開始一次故障轉移,將其中一個slave 提高爲新的 master ,將其餘的 slave 將從新配置使用新的 master 同步,並使用redis 的服務器應用程序在鏈接時受到使用新的地址鏈接; 
配置提供者(Configuration provider),sentinel 做爲在集羣中的權威來源,客戶端鏈接到 sentinel 來獲取某個服務的當前 redis 主服務器的地址和其餘信息。當前故障轉移發生時,sentinel 會報告新地址。sql

哨兵機制實現

1.若是要想進行哨兵配置及使用,請確保你的主機上已經準備好了Redis服務,本次將在一臺主機上模擬哨兵機制,如今的實現原則:一臺主機運行三個哨兵,而且該哨兵運行端口不一樣,可是這三個哨兵都要去監控同一個master的地址。

/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis-6379.conf /usr/local/redis/bin/redis-server /usr/local/redis/conf/redis-6380.conf /usr/local/redis/bin/redis-server /usr/local/redis/conf/redis-6381.conf

2.經過redis源代碼拷貝出哨兵運行程序: 
cp /usr/local/src/redis-3.2.9/src/redis-sentinel /usr/local/redis/bin/

3.全部的哨兵若是要想運行必定要準備出一個配置文件:sentinel.conf;

  • 對於此配置文件已經給出了一個參考模版:/usr/local/src/redis-3.2.9/sentinel.conf

4.創建sentinel-26379.conf配置文件:vim /usr/local/redis/conf/sentinel-26379.conf

  • 創建一個哨兵的配置文件目錄:mkdir -p /usr/data/redis/{sentinel-26379,sentinel-26380,sentinel-26381}

配置哨兵監聽端口:port 26379 
配置哨兵的工做目錄:dir /usr/data/redis/sentinel-26379 
設置監控的master:sentinel monitor mymaster 192.168.125.161 6379 2

備註: 
設置的mymaster只是一個表明名稱,若是你一個哨兵監控多個master,則這個名稱必定要有所不一樣,然後 2 表示若是有兩個哨兵認爲你出現了問題,則你應該下線選舉出新的master

設置master的認證信息:sentinel auth-pass mymaster mldnjava 
設置master不活躍的時間:sentinel down-after-milliseconds mymaster 30000 
選舉新的master失敗時間:sentinel failover-timeout mymaster 180000 
只有一個master同步:sentinel parallel-syncs mymaster 1 
撤銷Redis保護模式:protected-mode no

隨後按照這樣的配置分別創建sentinel-26380.conf、sentinel-26381.conf兩個配置文件。

cp /usr/local/redis/conf/sentinel-26379.conf /usr/local/redis/conf/sentinel-26380.conf cp /usr/local/redis/conf/sentinel-26379.conf /usr/local/redis/conf/sentinel-26381.conf

建議將此時的配置作一個副本保留一下:cp /usr/local/redis/conf/* /usr/data/redis/back/

5.啓動三個哨兵進程:

/usr/local/redis/bin/redis-sentinel /usr/local/redis/conf/sentinel-26379.conf /usr/local/redis/bin/redis-sentinel /usr/local/redis/conf/sentinel-26380.conf /usr/local/redis/bin/redis-sentinel /usr/local/redis/conf/sentinel-26381.conf

經過哨兵的信息輸出能夠發現以下特色:

  • +slave :當一個哨兵啓動以後若是已經肯定能夠鏈接到了master節點,則自動追加全部的slave節點;
  • +sentinel :每當啓動一個新的哨兵進程後會自動進行哨兵增長的信息提示;

6.直接kill掉當前監控的master主機,隨後會發現有以下提示信息:

  • +sdown master mymaster 192.168.125.161 6379 :當前的master主機已經下線了;
  • +vote-for-leader :進行從新的投票選舉;
  • +slave-reconf-sent slave 192.168.125.161:6381 :從主機會自動修改redis.conf配置文件;
  • +switch-master mymaster 192.168.125.161 6379 192.168.125.161 6380 :6380爲新的master;

7.若是此時的6379的進程又從新啓動成功了,那麼這個時候能夠考慮經過命令作一個從的設置,必定要求設置好redis-6379.conf配置文件中的masterauth屬性,若是不進行此項配置則沒法鏈接到master主機。

  • 同時也能夠發現全部哨兵文件對應的配置內容已經發生了改變,證實在整個哨兵的運行機制裏面,全部的配置文件都有可能出現更改。

Jedis訪問哨兵機制

如今爲止已經成功的實現了哨兵處理機制,可是對於程序的編寫依然須要注意一點,若是要進行哨兵的處理操做,那麼必定要求經過哨兵來取得可用的master地址。

package cn.mldn.jedis; import java.util.HashSet; import java.util.Set; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.JedisSentinelPool; public class JedisSentinel { public static final String MASTER_NAME = "mymaster" ; // 定義哨兵的Master配置名稱 public static final int TIMEOUT = 2000 ; // 鏈接超時時間 public static final String REDIS_AUTH = "mldnjava" ; // 認證密碼 public static final int MAX_TOTAL = 1000 ; // 設置最大鏈接數 public static final int MAX_IDLE = 200 ; // 設置最小維持鏈接數 public static final int MAX_WAIT_MILLIS = 1000 ; // 設置最大等待時間 public static void main(String[] args) { // 若是要經過哨兵機制進行Redis訪問,那麼必需要明確的設置出全部可使用的哨兵的地址與端口 Set<String> sentinels = new HashSet<String>() ; // 設置全部的哨兵的處理地址信息 sentinels.add("192.168.125.161:26379") ; // 哨兵的地址 sentinels.add("192.168.125.161:26380") ; // 哨兵的地址 sentinels.add("192.168.125.161:26381") ; // 哨兵的地址 // 首先若是要想使用Jedis鏈接池,則必須有一個類能夠保存全部鏈接池相關屬性的配置項 JedisPoolConfig poolConfig = new JedisPoolConfig() ; poolConfig.setMaxTotal(MAX_TOTAL); // 設置最大鏈接數 poolConfig.setMaxIdle(MAX_IDLE); // 設置空閒的鏈接數 poolConfig.setMaxWaitMillis(MAX_WAIT_MILLIS);// 最大等待時間 // 此時全部的鏈接應該經過哨兵機制取得,因此這個時候應該使用JedisSentinelPool對象 JedisSentinelPool pool = new JedisSentinelPool(MASTER_NAME, sentinels, poolConfig); // 創建一個哨兵的鏈接池 Jedis jedis = pool.getResource() ; // 經過鏈接池獲取鏈接對象 jedis.auth(REDIS_AUTH) ; System.out.println(jedis); jedis.set("mldn", "www.mldn.cn") ; jedis.close(); pool.close(); // 關閉鏈接池 } }

SpringData訪問哨兵

在以前使用的SpringData進行Redis訪問的時候採用的是一個Spring內部支持的鏈接池,而且只有一個鏈接地址,可是若是要進行哨兵的配置,則須要將全部的哨兵地址都進行配置。

1.修改redis.properties配置文件,追加全部的哨兵配置地址:

# 追加全部的哨兵的訪問處理地址以及對應的端口號 redis.sentinel-1.host=192.168.68.165 redis.sentinel-2.host=192.168.68.165 redis.sentinel-3.host=192.168.68.165 redis.sentinel-1.port=26379 redis.sentinel-2.port=26380 redis.sentinel-3.port=26381 # 定義哨兵的master的名稱 redis.sentinel.master.name=mymaster # Redis的認證信息,認證信息密碼 redis.password=mldnjava # Redis鏈接的超時時間 redis.timeout=2000 # 設置最大的可用鏈接數 redis.pool.maxTotal=100 # 最小維持的可用鏈接數 redis.pool.maxIdle=20 # 最大等待時間 redis.pool.maxWaitMillis=2000

2.修改spring-redis.xml配置文件,在這個配置文件裏面須要將以前的鏈接池作一些更改:

<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd"> <!-- 若是要進行Redis處理用戶應該不去關注具體的序列化或反序列化操做,這一切都應該交給SpringData處理 --> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="connectionFactory"/> <!-- 定義Redis鏈接工廠 --> <property name="keySerializer"> <!-- 定義序列化Key的程序處理類 --> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> <property name="valueSerializer"> <!-- 處理value數據的操做 --> <!-- 明確表示若是要進行value數據保存的時候,保存的對象必定要使用JDK提供的序列化處理類 --> <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/> </property> <property name="hashKeySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/> </property> <property name="hashValueSerializer"> <!-- 處理hash數據的保存 --> <bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/> </property> </bean> <!-- 進行全部的哨兵地址的配置項 --> <bean id="sentinelsConfiguration" class="org.springframework.data.redis.connection.RedisSentinelConfiguration"> <property name="master"><!-- 配置master的節點名稱 --> <bean class="org.springframework.data.redis.connection.RedisNode"> <!-- 經過資源文件讀取出master的名稱進行配置 --> <property name="name" value="${redis.sentinel.master.name}"/> </bean> </property> <!-- 配置全部哨兵的鏈接地址信息 --> <property name="sentinels"> <set> <bean class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="${redis.sentinel-1.host}"/> <constructor-arg name="port" value="${redis.sentinel-1.port}"/> </bean> <bean class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="${redis.sentinel-2.host}"/> <constructor-arg name="port" value="${redis.sentinel-2.port}"/> </bean> <bean class="org.springframework.data.redis.connection.RedisNode"> <constructor-arg name="host" value="${redis.sentinel-3.host}"/> <constructor-arg name="port" value="${redis.sentinel-3.port}"/> </bean> </set> </property> </bean> <!-- 首先進行Jedis鏈接池的相關配置 --> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="${redis.pool.maxTotal}"/> <!-- 最大可用鏈接數 --> <property name="maxIdle" value="${redis.pool.maxIdle}"/> <!-- 最小維持鏈接數 --> <property name="maxWaitMillis" value="${redis.pool.maxWaitMillis}"/> <!-- 最大等待時間 --> </bean> <!-- 進行ConnectionFactory的配置 --> <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <constructor-arg name="sentinelConfig" ref="sentinelsConfiguration"/> <property name="poolConfig" ref="jedisPoolConfig"/> <!-- 引用進行鏈接池的配置項 --> <property name="password" value="${redis.password}"/> <!-- 定義的是鏈接密碼,認證密碼 --> </bean> </beans>

twemproxy代理機制

無論你如今電腦性能有多好,只要你運行了Redis,那麼就有可能形成一種很是可怕局面:你電腦的內存將馬上被佔滿,並且一臺Redis數據庫的性能終歸是有限制的,那麼如今若是要求保證用戶的執行速度快,就須要使用集羣的設計。而對於集羣的設計主要的問題就是解決單實例Redis的性能瓶頸。 
這裏寫圖片描述

twemproxy代理概述

Twemproxy是一個專門爲了這種nosql數據庫設計的一款代理工具軟件,這個工具軟件最大的特徵是能夠實現數據的分片處理。所謂的分片指的是根據必定的算法將要保存的數據保存到不一樣的節點之中。 
有了分片以後數據的保存節點就可能有無限多個,可是理論上若是要真進行集羣的搭建,每每要求三臺節點起步。

Twemproxy

  • Twemproxy,也叫 nutcraker。是一個Twitter開源的一個redis和memcache快速/輕量級代理服務器;Twemproxy是一個快速的單線程代理程序,支持Memcached ASCII協議和更新的redis協議;
  • Twemproxy經過引入一個代理層,能夠將其後端的多臺redis或memcached實例進行統一管理與分配,使應用程序只須要在Twemproxy 上進行操做,而不用關係後面具體有多少個真實的redis或memcached存儲;
  • github地址:https://github.com/twitter/twemproxy

Twemproxy 的特性

  • 支持失敗節點自動刪除 
    • 能夠設置從新鏈接該節點的時間
    • 能夠設置鏈接多少次以後刪除該節點
  • 支持設置HashTag 
    • 經過HashTag能夠本身設定將兩個key哈希到同一個實例上去
  • 減小與redis的直接鏈接數 
    • 保持與redis的長鏈接
    • 減小了客戶端直接與服務器鏈接的連接數量
  • 自動分片到後端多個redis實例上 
    • 多種hash算法:MD五、CRC1六、CRC3二、CRC32a、hsieh、murmur、Jenkins
    • 多種分片算法:ketama(一致性hash算法的一種實現)、modular、random
    • 能夠設置後端實例的權重
  • 避免單節點問題 
    • 能夠平行部署多個代理層,經過HAProxy作負載均衡,將redis的讀寫分散到多個twemproxy上。
  • 支持狀態監控 
    • 可設置狀態監控IP和端口,訪問IP和端口能夠獲得一個json格式的狀態信息串
    • 可設置監控信息刷新間隔時間
  • 使用pipelining處理請求和響應 
    • 鏈接複用,內存服用
    • 將多個鏈接請求,組成redis pipelining統一redis請求
  • 並非支持全部redis命令 
    • 不支持redis的事務操做
    • 使用SIDFF,SDIFFSTORE,SINTER,SINTERSTORE,SMOVE,SUNION and SUNIONSTORE 命令須要保證key都在同一個分片上。

最主要功能:用戶再也不直接操做真正的Redis,並且支持高性能的數據訪問,並且支持分片處理,能夠操做Redis集羣。

配置Redis集羣主機

本次預計使用三臺Redis服務器,而且考慮到實際的應用環境,這三臺的Master分別有各自的兩個slave主機。因而如今給出本次使用的主機列表:

主機名稱 IP地址 描述
tw-redis-server-a 192.168.125.162 Reids master數據服務:6379 Reids slave數據服務:6380 Reids slave 數據服務:6381
tw-redis-server-b 192.168.125.163 Reids master 數據服務:6379 Reids slave 數據服務:6380 Reids slave 數據服務:6381
tw-redis-server-c 192.168.125.164 Reids master 數據服務:6379 Reids slave 數據服務:6380 Reids slave 數據服務:6381

1.tw-redis-server-*考慮到主機的通用性,全部的主機都建議修改主機名稱以及對應的hosts文件:

  • 修改hostname:vim /etc/hostname,修改完成以後從新啓動;
  • 修改hosts:vim /etc/hosts,作好ip地址與主機名稱的映射;

2.tw-redis-server-a本次主機經過以前的配置得來裏面已經實現了基本的配置環境,可是依然須要由用戶本身來配置主從關係:

  • 修改6380端口配置:vim /usr/local/redis/conf/redis-6380.conf
slaveof 192.168.125.162 6379 masterauth mldnjava
  • 修改6381端口配置:vim /usr/local/redis/conf/redis-6381.conf
slaveof 192.168.125.162 6379 masterauth mldnjava

3.tw-redis-server-*啓動全部Redis數據庫的實例

/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis-6379.conf /usr/local/redis/bin/redis-server /usr/local/redis/conf/redis-6380.conf /usr/local/redis/bin/redis-server /usr/local/redis/conf/redis-6381.conf

此時就至關於有就臺Redis數據庫,然後有三臺是Master節點,六臺爲Slave節點。

4.tw-redis-server-*查看從節點狀態:

/usr/local/redis/bin/redis-cli -h 192.168.125.162 -p 6379 -a mldnjava info replication

一臺主機的redis客戶端,只要你鏈接的ip、端口、密碼正確,那麼均可以鏈接到任意的主機上。

編譯與配置twemproxy

如今關鍵的問題就在於如何進行Redis分片處理,而分片處理的關鍵工具就是twemproxy工具,可是此工具給出的是一個源代碼,因此使用以前必定要先進行編譯處理。

1.tw-proxy-server-a將twemproxy-0.4.1.tar.gz源代碼開發包上傳到Linux系統之中,隨後將其解壓縮到源代碼目錄:

tar xzvf /srv/ftp/twemproxy-0.4.1.tar.gz -C /usr/local/src/

2.tw-proxy-server-a進入到源代碼所在的目錄:cd /usr/local/src/twemproxy-0.4.1/

  • 首先要使用autoreconf工具生成一些編譯的程序文件:autoreconf -fvi
  • 創建一個twemproxy編譯後的工做目錄:mkdir -p /usr/local/twemproxy
  • 進行編譯的目錄配置:./configure --prefix=/usr/local/twemproxy
  • 進行源代碼的編譯與安裝:make && make install

3.tw-proxy-server-a隨後須要配置一個twemproxy的配置文件,這個配置文件考慮到隨後與其它機制的整合,名稱必定要設置爲 redis_master.conf :

  • 首先創建一個保存配置文件的目錄:mkdir -p /usr/local/twemproxy/conf
  • 拷貝文件:cp /usr/local/src/twemproxy-0.4.1/conf/nutcracker.yml /usr/local/twemproxy/conf/redis_master.conf

4.tw-proxy-server-a編輯redis_master.conf文件:vim /usr/local/twemproxy/conf/redis_master.conf

redis_master: listen: 0.0.0.0:22121 hash: fnv1a_64 distribution: ketama auto_eject_hosts: true redis: true redis_auth: mldnjava server_retry_timeout: 2000 server_failure_limit: 1 servers: - 192.168.125.162:6379:1 - 192.168.125.163:6379:1 - 192.168.125.164:6379:1

以上配置的 redis_master 的名稱與配置文件是同樣的,並且必須同樣,同時在本文件裏面配置了redis訪問密碼,以及twemproxy全部可能代理到的redis服務器master節點。

5.tw-proxy-server-a{坑}twemproxy自己自帶有一個配置文件的檢測工具:

/usr/local/twemproxy/sbin/nutcracker -t /usr/local/twemproxy/conf/redis_master.conf

6.tw-proxy-server-a啓動twemproxy的服務:

  • 首先爲了啓動方便必定要設置一些數據的保存目錄:mkdir -p /usr/local/twemproxy/{pid,logs}
/usr/local/twemproxy/sbin/nutcracker -c /usr/local/twemproxy/conf/redis_master.conf -p /usr/local/twemproxy/pid/redis_master.pid -o /usr/local/twemproxy/logs/redis_master.log -d

7.tw-proxy-server-a這個時候一旦twemproxy啓動以後就表示該進程是一個redis的代理進程, 全部的服務能夠經過twemproxy訪問,而它的地址是:22121,隨意找到一個redis客戶端便可。 
/usr/local/redis/bin/redis-cli -h 192.168.68.170 -p 22121 -a mldnjava 
如今鏈接的直接爲代理,隨後找到各自的redis數據庫的服務。 
/usr/local/redis/bin/redis-cli -h 192.168.68.167 -p 6379 -a mldnjava

8.編寫java程序經過jedis訪問:

package cn.mldn.jedis; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; public class TwemproxyDemo { public static final String REDIS_HOST = "192.168.68.170" ; // 主機地址 public static final int REDIS_PORT = 22121 ; // 端口號 public static final int TIMEOUT = 2000 ; // 鏈接超時時間 public static final String REDIS_AUTH = "mldnjava" ; // 認證密碼 public static final int MAX_TOTAL = 1000 ; // 設置最大鏈接數 public static final int MAX_IDLE = 200 ; // 設置最小維持鏈接數 public static final int MAX_WAIT_MILLIS = 1000 ; // 設置最大等待時間 public static final boolean TEST_ON_BORROW = true ; // 是否進行可用測試 public static void main(String[] args) { // 首先若是要想使用Jedis鏈接池,則必須有一個類能夠保存全部鏈接池相關屬性的配置項 JedisPoolConfig poolConfig = new JedisPoolConfig() ; poolConfig.setMaxTotal(MAX_TOTAL); // 設置最大鏈接數 poolConfig.setMaxIdle(MAX_IDLE); // 設置空閒的鏈接數 poolConfig.setMaxWaitMillis(MAX_WAIT_MILLIS);// 最大等待時間 poolConfig.setTestOnBorrow(TEST_ON_BORROW); // 是否要進行鏈接測試,以保證返回的鏈接爲可用鏈接 JedisPool pool = new JedisPool(poolConfig,REDIS_HOST,REDIS_PORT,TIMEOUT,REDIS_AUTH) ; Jedis jedis = pool.getResource() ; // 經過鏈接池獲取鏈接對象 for (int x = 0 ; x < 1000 ; x ++) { jedis.set("mldn-" + x, "www.mldn.cn") ; } jedis.close(); pool.close(); // 關閉鏈接池 } }

Twemproxy與Sentinel集成

Twemproxy若是要與Redis集成使用的是RedisMaster節點,由於只有Master節點才具有有寫功能,而全部的Slave節點只具有有隻讀的數據功能,如今的思考點暫時不放在twemproxy上,而如今的問題集中在後端的全部Redis節點之中,由於Redis存在有主從關係,那麼一旦某一個RedisMaster被幹掉了,則必定要從新選舉出一個新的Master節點,可是這個時候會出現有一個問題:twemproxy所使用的配置文件是單獨存在的:

redis_master: listen: 0.0.0.0:22121 hash: fnv1a_64 distribution: ketama auto_eject_hosts: true redis: true redis_auth: mldnjava server_retry_timeout: 2000 server_failure_limit: 1 servers: - 192.168.125.162:6379:1 - 192.168.125.163:6379:1 - 192.168.125.164:6379:1

Redis集羣中進行哨兵配置

若是要進行哨兵機制運行至少須要有三臺或以上的主機,本次已經有了三臺Redis集羣,因此爲了方便,在以前的三臺主機上進行Sentinel配置,如今主機所運行的進程關係以下:

主機名稱 IP地址 描述
tw-redis-server-a 192.168.125.162 Redis服務637九、6380、6381 Sentinel服務 26379
tw-redis-server-b 192.168.125.163 Redis服務637九、6380、6381 Sentinel服務 26379
tw-redis-server-c 192.168.125.164 Redis服務637九、6380、6381 Sentinel服務 26379
tw-proxy-server-a 192.168.125.165 Twemproxy代理服務 Sentinel服務26379

1.tw-redis-server-*在全部的主機上創建哨兵機制的保存數據目錄:mkdir -p /usr/data/redis/sentinel

2.tw-redis-server-a進行哨兵配置文件的編寫:vim /usr/local/redis/conf/sentinel.conf

port 26379 dir /usr/data/redis/sentinel protected-mode no sentinel monitor redis_master_group1 192.168.125.162 6379 2 sentinel auth-pass redis_master_group1 mldnjava sentinel down-after-milliseconds redis_master_group1 10000 sentinel failover-timeout redis_master_group1 10000 sentinel parallel-syncs redis_master_group1 1 sentinel monitor redis_master_group2 192.168.125.163 6379 2 sentinel auth-pass redis_master_group2 mldnjava sentinel down-after-milliseconds redis_master_group2 10000 sentinel failover-timeout redis_master_group2 10000 sentinel parallel-syncs redis_master_group2 1 sentinel monitor redis_master_group3 192.168.125.164 6379 2 sentinel auth-pass redis_master_group3 mldnjava sentinel down-after-milliseconds redis_master_group3 10000 sentinel failover-timeout redis_master_group3 10000 sentinel parallel-syncs redis_master_group3 1

3.tw-redis-server-a將哨兵的配置文件發送到其它主機上: 
拷貝到 tw-redis-server-b 主機:scp /usr/local/redis/conf/sentinel.conf 192.168.125.163:/usr/local/redis/conf/ 
拷貝到 tw-redis-server-c 主機:scp /usr/local/redis/conf/sentinel.conf 192.168.125.164:/usr/local/redis/conf/

4.tw-redis-server-*考慮到哨兵機制運行以後會進行配置文件的變動,那麼最好的作法是將這些配置文件作一個副本,這樣測試起來會比較方便:cp /usr/local/redis/conf/* /usr/data/redis/back/

5.tw-redis-server-*啓動哨兵進程:/usr/local/redis/bin/redis-sentinel /usr/local/redis/conf/sentinel.conf

twemproxy整合哨兵機制

若是要想在twemproxy之中與哨兵整合,而且實現twemproxy進程的從新啓動,那麼有一個前提必須有保證:你的twemproxy運行的主機必定要提供有哨兵機制,目的是爲了與其它的哨兵進行整合處理。

1.tw-redis-server-a將哨兵的配置文件拷貝到tw-proxy-server-a主機上;

scp /usr/data/redis/back/sentinel.conf 192.168.68.170:/usr/local/redis/conf; 

2.tw-proxy-server-a經過源代碼文件拷貝出哨兵進程的啓動項:cp /usr/local/src/redis-3.2.9/src/redis-sentinel /usr/local/redis/bin/

3.tw-proxy-server-a啓動哨兵機制,這個哨兵機制是爲了讓Shell腳本能夠整合到全部的哨兵機制裏;

/usr/local/redis/bin/redis-sentinel /usr/local/redis/conf/sentinel.conf

4.tw-proxy-server-a爲了方便進行shell腳本的保存在twemproxy程序目錄中建立有一個sh的目錄:mkdir -p /usr/local/twemproxy/sh

5.tw-proxy-server-a創建一個能夠進行哨兵重啓twemproxy進程的shell腳本: 
編輯命令:vim /usr/local/twemproxy/sh/client-reconfig.sh

#!/bin/sh # monitor_name="$1" master_old_ip="$4" master_old_port="$5" master_new_ip="$6" master_new_port="$7" twemproxy_name=$(echo $monitor_name |awk -F'_' '{print $1"_"$2}') twemproxy_bin="/usr/local/twemproxy/sbin/nutcracker" twemproxy_conf="/usr/local/twemproxy/conf/${twemproxy_name}.conf" twemproxy_pid="/usr/local/twemproxy/pid/${twemproxy_name}.pid" twemproxy_log="/usr/local/twemproxy/logs/${twemproxy_name}.log" twemproxy_cmd="${twemproxy_bin} -c ${twemproxy_conf} -p ${twemproxy_pid} -o ${twemproxy_log} -d" sed -i "s/${master_old_ip}:${master_old_port}/${master_new_ip}:${master_new_port}/" ${twemproxy_conf} ps -ef |grep "${twemproxy_cmd}" |grep -v grep |awk '{print $2}'|xargs kill ${twemproxy_cmd} sleep 1 ps -ef |grep "${twemproxy_cmd}" |grep -v grep

6.tw-proxy-server-a爲腳本授予所有執行權限:chmod 777 /usr/local/twemproxy/sh/client-reconfig.sh

7.tw-proxy-server-a如今要鏈接本機的哨兵進程,這樣才能夠與此腳本文件有關聯:

/usr/local/redis/bin/redis-cli -h 192.168.125.162 -p 26379 sentinel set redis_master_group1 client-reconfig-script /usr/local/twemproxy/sh/client-reconfig.sh /usr/local/redis/bin/redis-cli -h 192.168.125.162 -p 26379 sentinel set redis_master_group2 client-reconfig-script /usr/local/twemproxy/sh/client-reconfig.sh /usr/local/redis/bin/redis-cli -h 192.168.125.162 -p 26379 sentinel set redis_master_group3 client-reconfig-script /usr/local/twemproxy/sh/client-reconfig.sh

那麼此時哨兵機制一旦發生了從新的選舉以後,那麼會馬上從新啓動twemproxy的相關進程。

8.tw-redis-server-a殺死掉redis-6379服務進程,這樣master就消失了,消失以後應該會觸發腳本,會從新配置redis_master.conf文件,這個時候對應在twemproxy主機上的哨兵會自動進行twemproxy的進程從新啓動,以此保證twemproxy中Redis主機的高可用狀態。

HAProxy負載均衡

Twemproxy主要功能在於數據的分片處理,並且會發如今整個的Redis集羣裏面,若是用戶要想訪問Redis集羣必須經過Twemproxy,因而這個時候就有可能形成一種問題:

  • 你後面的Redis集羣必定速度暴快,由於一堆的數據庫服務;
  • 全部的性能都卡在了代理上。

HAProxy:haproxy是一個開源的,高性能的,基於TCP第四層和http第七層應用的千萬級高併發負載均衡軟件;

HAProxy優勢:

  • 最高能夠同時維護40000-50000個併發鏈接。單位時間內處理最大的請求數爲20000.最大數據處理能力可達10GBPS
  • 支持多餘8種負載均衡算法,同時也支持session保持
  • 支持虛擬主機功能
  • 擁有服務器性能監控工具。

配置HAProxy

如今爲了觀察問題準備出來了三臺twemproxy主機,然後如今再須要準備出一臺haproxy主機tw-haproxy-server-a。然後經過這個haproxy主機先進行haproxy運行的處理。

1.tw-haproxy-server-a將haproxy的開發包上傳到系統之中,隨後爲其進行解壓縮控制:tar xzvf /srv/ftp/haproxy-1.5.18.tar.gz -C /usr/local/src/

2.tw-haproxy-server-a進入到haproxy源代碼目錄:cd /usr/local/src/haproxy-1.5.18/

  • 創建一個Haproxy編譯後的保存目錄:mkdir -p /usr/local/haproxy
  • 若是要想進行HAProxy的處理必定要選擇好你當前的系統架構的信息:
make TARGET=linux26 PREFIX=/usr/local/haproxy ARCH=x86_64
  • 進行HAProxy的安裝處理:make install PREFIX=/usr/local/haproxy

安裝完成以後會在 /usr/local/haproxy 目錄下存在有:doc、sbin、share三個目錄;

3.tw-haproxy-server-a創建一個haproxy的數據保存工做目錄:mkdir -p /usr/data/haprox

4.tw-haproxy-server-a經過源代碼拷貝出一個配置文件到指定的目錄之中;

cp /usr/local/src/haproxy-1.5.18/examples/haproxy.cfg /usr/local/haproxy/

5.tw-haproxy-server-a編輯 haproxy.cfg 配置文件:vim /usr/local/haproxy/haproxy.cfg

global
        log 127.0.0.1 local0 log 127.0.0.1 local1 notice #log loghost local0 info maxconn 4096 chroot /usr/local/haproxy pidfile /usr/data/haproxy/haproxy.pid uid 99 gid 99 daemon #debug #quiet defaults log global mode tcp option httplog option dontlognull retries 3 redispatch maxconn 2000 contimeout 5000 clitimeout 50000 srvtimeout 50000 listen appli1-rewrite 0.0.0.0:10001 cookie SERVERID rewrite balance roundrobin option abortonclose option redispatch retries 3 maxconn 2000 timeout connect 5000 timeout client 50000 timeout server 50000 listen proxy_status bind :16001 mode tcp balance roundrobin server tw_proxy_1 192.168.125.165:22121 check inter 10s server tw_proxy_2 192.168.125.166:22121 check inter 10s server tw_proxy_3 192.168.125.167:22121 check inter 10s frontend admin_stats bind :7777 mode http stats enable option httplog maxconn 10 stats refresh 30s stats uri /admin stats auth mldn:java stats hide-version stats admin if TRUE

6.tw-haproxy-server-a須要進行haproxy的進程啓動:

/usr/local/haproxy/sbin/haproxy -f /usr/local/haproxy/haproxy.cfg

7.若是如今要想確認當前已經正常啓動,則能夠經過管理控制檯查看:http://192.168.125.165:7777/admin

  • 訪問的時候輸入以前配置好的認證名稱:mldn、java 
    這裏寫圖片描述

HAProxy測試

1.若是要想正常完成測試,必定要先保證Redis、sentinel、twemproxy的服務進程所有正常啓動;

  • tw-redis-server-* Redis進程應該是能夠正常啓動的:ps -ef | grep redis
  • tw-redis-server-、tw-proxy-server-從新配置哨兵文件:cp /usr/data/redis/back/sentinel.conf /usr/local/redis/conf/ 
    • 啓動哨兵:/usr/local/redis/bin/redis-server /usr/local/redis/conf/sentinel.conf

2.tw-proxy-server-*啓動twemproxy的進程:

/usr/local/twemproxy/sbin/nutcracker -c /usr/local/twemproxy/conf/redis_master.conf -p /usr/local/twemproxy/pid/redis_master.pid -o /usr/local/twemproxy/logs/redis_master.log -d

3.先保證各個 twemproxy 的節點能夠正常使用。

4.使用haproxy進行代理操,使用redis客戶端登陸:/usr/local/redis/bin/redis-cli -h 192.168.125.167 -p 16001 -a mldnjava

5.經過jedis的java客戶端進行數據訪問:

package cn.mldn.jedis; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; public class TwemproxyDemo { public static final String REDIS_HOST = "192.168.125.167" ; // 主機地址 public static final int REDIS_PORT = 16001 ; // 端口號 public static final int TIMEOUT = 2000 ; // 鏈接超時時間 public static final String REDIS_AUTH = "mldnjava" ; // 認證密碼 public static final int MAX_TOTAL = 1000 ; // 設置最大鏈接數 public static final int MAX_IDLE = 200 ; // 設置最小維持鏈接數 public static final int MAX_WAIT_MILLIS = 1000 ; // 設置最大等待時間 public static void main(String[] args) { // 首先若是要想使用Jedis鏈接池,則必須有一個類能夠保存全部鏈接池相關屬性的配置項 JedisPoolConfig poolConfig = new JedisPoolConfig() ; poolConfig.setMaxTotal(MAX_TOTAL); // 設置最大鏈接數 poolConfig.setMaxIdle(MAX_IDLE); // 設置空閒的鏈接數 poolConfig.setMaxWaitMillis(MAX_WAIT_MILLIS);// 最大等待時間 JedisPool pool = new JedisPool(poolConfig,REDIS_HOST,REDIS_PORT,TIMEOUT,REDIS_AUTH) ; Jedis jedis = pool.getResource() ; // 經過鏈接池獲取鏈接對象 for (int x = 0 ; x < 10000 ; x ++) { jedis.set("mldn-" + x, "www.mldn.cn") ; } jedis.close(); pool.close(); // 關閉鏈接池 } }

若是此時的程序出現有以下的錯誤信息:

Exception in thread "main" redis.clients.jedis.exceptions.JedisDataException: READONLY You can't write against a read only slave.

這裏寫圖片描述

Keepalived高可用機制

若是面對Redis集羣,只是依靠twemproxy的分片是不夠的,還須要有一系列的代理設計,例如:HAProxy能夠實現負載均衡設計。

Keepalived是一個基於VRRP協議來實現的服務高可用方案,能夠利用其來避免IP單點故障,相似的工具還有heartbeat、corosync、pacemaker。可是它通常不會單獨出現,而是與其餘負載均衡技術如lvs、haproxy、nginx一塊兒工做來達到集羣的高可用。 
下載地址:http://wwww.keepalived.org/

安裝與配置Keepalived組件

keepalived組件給出的是一個源代碼的開發包,因此你依然須要在你的系統之中進行編譯與配置處理。

1.tw-haproxy-server-a主機將keepalived開發包上傳到Linux系統之中,隨後將其進行解壓縮。

tar xzvf /srv/ftp/keepalived-1.2.24.tar.gz -C /usr/local/

2.tw-haproxy-server-a主機爲了配置方便進行一下改名處理:

mv /usr/local/keepalived-1.2.24/ /usr/local/keepalived

3.tw-haproxy-server-a主機進入到keepalived組件包的目錄:cd /usr/local/keepalived/

4.tw-haproxy-server-a主機進行編譯處理:

  • 進行編譯配置:./configure --prefix=/usr
  • 編譯與安裝:make && make install

5.tw-haproxy-server-a主機將keepalived的配置文件拷貝到 /etc/keepalived 目錄之中;

  • 創建一個新的目錄:mkdir -p /etc/keepalived
  • 拷貝配置文件:cp /usr/etc/keepalived/keepalived.conf /etc/keepalived/

6.tw-haproxy-server-a主機編輯keepalived.conf配置文件:vim /etc/keepalived/keepalived.conf

  • keepalived因爲須要進行虛擬IP的設計,因此首先要取得網卡名稱:cat /proc/net/dev、ifconfig,如今的名稱爲 ens33 ;
! Configuration File for keepalived global_defs { notification_email { acassen@firewall.loc failover@firewall.loc sysadmin@firewall.loc } notification_email_from Alexandre.Cassen@firewall.loc smtp_server 192.168.200.1 smtp_connect_timeout 30 router_id LVS_DEVEL vrrp_skip_check_adv_addr vrrp_strict vrrp_garp_interval 0 vrrp_gna_interval 0 } vrrp_instance VI_1 { state MASTER interface ens33 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.68.250 } } virtual_server 192.168.125.250 16001 { delay_loop 6 lb_algo rr lb_kind NAT persistence_timeout 50 protocol TCP real_server 192.168.125.168 16001 { weight 1 TCP_CHECK { connect_timeout 3 delay_before_retry 3 } } real_server 192.168.125.169 16001 { weight 1 TCP_CHECK { connect_timeout 3 delay_before_retry 3 } } }

7.tw-haproxy-server-b主機關閉 tw-haproxy-server-a 這臺虛擬機,然後將其克隆爲 tw-haproxy-server-b 主機。 
8.tw-haproxy-server-b主機修改 keepalived.conf 配置文件,必定要設置爲BACKUP,同時優先級別必定要下降。 
- 修改配置文件:vim /etc/keepalived/keepalived.conf

vrrp_instance VI_1 { state BACKUP interface ens33 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.68.250 } } virtual_server 192.168.125.250 16001 { delay_loop 6 lb_algo rr lb_kind NAT persistence_timeout 50 protocol TCP real_server 192.168.125.168 16001 { weight 1 TCP_CHECK { connect_timeout 3 delay_before_retry 3 } } real_server 192.168.125.169 16001 { weight 1 TCP_CHECK { connect_timeout 3 delay_before_retry 3 } } }

9.tw-haproxy-server-*啓動HAProxy:

/usr/local/haproxy/sbin/haproxy -f /usr/local/haproxy/haproxy.cfg

10.tw-haproxy-server-*啓動keepalived服務:service keepalived start

  • 查看一下keepalived相關進程:ps -ef | grep keepalived
  • 直接查看keepalived狀態:service keepalived status
  • 中止keepalived服務:service keepalived stop

11.此時若是在進行訪問,必定要使用VIP進行訪問。

  • 訪問haproxyhttp://192.168.125.250:7777/admin
相關文章
相關標籤/搜索