第三章 Redis/SSDB+Twemproxy安装与使用
目前對于互聯網公司不使用Redis的很少,Redis不僅僅可以作為key-value緩存,而且提供了豐富的數據結果如set、list、map等,可以實現很多復雜的功能;但是Redis本身主要用作內存緩存,不適合做持久化存儲,因此目前有如SSDB、ARDB等,還有如京東的JIMDB,它們都支持Redis協議,可以支持Redis客戶端直接訪問;而這些持久化存儲大多數使用了如LevelDB、RocksDB、LMDB持久化引擎來實現數據的持久化存儲;京東的JIMDB主要分為兩個版本:LevelDB和LMDB,而我們看到的京東商品詳情頁就是使用LMDB引擎作為存儲的,可以實現海量KV存儲;當然SSDB在京東內部也有些部門在使用;另外調研過得如豆瓣的beansDB也是很不錯的。具體這些持久化引擎之間的區別可以自行查找資料學習。
?
Twemproxy是一個Redis/Memcached代理中間件,可以實現諸如分片邏輯、HashTag、減少連接數等功能;尤其在有大量應用服務器的場景下Twemproxy的角色就凸顯了,能有效減少連接數。
?
Redis安裝與使用?
1、下載redis并安裝
Java代碼??通過如上步驟構建完畢。
?
2、后臺啟動Redis服務器
Java代碼???
3、查看是否啟動成功
Java代碼???
4、進入客戶端
Java代碼???
5、執行如下命令??
Java代碼??通過如上命令可以看到我們的Redis安裝成功。更多細節請參考http://redis.io/。
?
SSDB安裝與使用
1、下載SSDB并安裝
Java代碼???
2、后臺啟動SSDB服務器
Java代碼???
3、查看是否啟動成功? ?
Java代碼???
4、進入客戶端
Java代碼??因為SSDB支持Redis協議,所以用Redis客戶端也可以訪問?
?
5、執行如下命令
Java代碼??安裝過程中遇到錯誤請參考http://ssdb.io/docs/zh_cn/install.html;對于SSDB的配置請參考官方文檔https://github.com/ideawu/ssdb。
?
Twemproxy安裝與使用
首先需要安裝autoconf、automake、libtool工具,比如ubuntu可以使用如下命令安裝
Java代碼????
1、下載Twemproxy并安裝
Java代碼??此處根據要注意,如上安裝方式在有些服務器上可能在大量如mset時可能導致Twemproxy崩潰,需要使用如?CFLAGS="-O1" ./configure && make或CFLAGS="-O3 -fno-strict-aliasing" ./configure && make安裝。
?
2、配置
Java代碼???
Java代碼???
3、啟動Twemproxy代理
Java代碼??-d指定后臺啟動? -c指定配置文件;此處我們指定了代理端口為1111,其他配置的含義后續介紹。
?
4、查看是否啟動成功??
Java代碼???
5、進入客戶端
Java代碼???
6、執行如下命令?
Java代碼??Twemproxy文檔請參考https://github.com/twitter/twemproxy。
?
到此基本的安裝就完成了。接下來做一些介紹。
?
Redis設置
基本設置
Java代碼???
Redis內存?
Java代碼???
而如Memcached是真正的LRU,此處要根據實際情況設置緩存策略,如緩存用戶數據時可能帶上了過期時間,此時采用volatile-lru即可;而假設我們的數據未設置過期時間,此時可以考慮使用allkeys-lru/allkeys->random;假設我們的數據不允許從內存刪除那就使用noeviction。
?
內存大小盡量在系統內存的60%~80%之間,因為如客戶端、主從時復制時都需要緩存區的,這些也是耗費系統內存的。
?
Redis本身是單線程的,因此我們可以設置每個實例在6-8GB之間,通過啟動更多的實例提高吞吐量。如128GB的我們可以開啟8GB * 10個實例,充分利用多核CPU。
?
Redis主從
實際項目時,為了提高吞吐量,我們使用主從策略,即數據寫到主Redis,讀的時候從從Redis上讀,這樣可以通過掛載更多的從來提高吞吐量。而且可以通過主從機制,在葉子節點開啟持久化方式防止數據丟失。
Java代碼??此處需要根據實際情況設置client-output-buffer-limit slave和 repl-backlog-size;比如如果網絡環境不好,從與主經常斷開,而每次設置的數據都特別大而且速度特別快(大量設置html片段)那么就需要加大repl-backlog-size。?
?
主從示例
Java代碼???
將端口分別改為port 6660和port 6661,然后啟動
Java代碼???
查看是否啟動
Java代碼???
進入從客戶端,掛主
Java代碼???進入主
Java代碼???
進入從???
?
Java代碼??此時可以看到主從掛載成功,可以進行主從復制了。使用slaveof no one斷開主從。
?
Redis持久化
Redis雖然不適合做持久化存儲,但是為了防止數據丟失有時需要進行持久化存儲,此時可以掛載一個從(葉子節點)只進行持久化存儲工作,這樣假設其他服務器掛了,我們可以通過這個節點進行數據恢復。
Redis持久化有RDB快照模式和AOF追加模式,根據自己需求進行選擇。
?
RDB持久化
Java代碼??可以通過set一個數據,然后很快的kill掉redis進程然后再啟動會發現數據丟失了。
?
AOF持久化???
AOF(append only file)即文件追加模式,即把每一個用戶操作的命令保存下來,這樣就會存在好多重復的命令導致恢復時間過長,那么可以通過相應的配置定期進行AOF重寫來減少重復。
Java代碼??此處的appendfsync?everysec可以認為是RDB和AOF的一個折中方案。
?
#當bgsave出錯時停止寫(MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk.),遇到該錯誤可以暫時改為no,當寫成功后再改回yes
stop-writes-on-bgsave-error yes
?
更多Redis持久化請參考http://redis.readthedocs.org/en/latest/topic/persistence.html。
?
Redis動態調整配置
獲取maxmemory(10mb)?
Java代碼???
設置新的maxmemory(20mb)
Java代碼????
但是此時重啟redis后該配置會丟失,可以執行如下命令重寫配置文件
Java代碼??注意:此時所以配置包括主從配置都會重寫。
?
Redis執行Lua腳本
Redis客戶端支持解析和處理lua腳本,因為Redis的單線程機制,我們可以借助Lua腳本實現一些原子操作,如扣減庫存/紅包之類的。此處不建議使用EVAL直接發送lua腳本到客戶端,因為其每次都會進行Lua腳本的解析,而是使用SCRIPT LOAD+?EVALSHA進行操作。未來不知道是否會用luajit來代替lua,讓redis lua腳本性能更強。
?
到此基本的Redis知識就講完了。
?
Twemproxy設置
一旦涉及到一臺物理機無法存儲的情況就需要考慮使用分片機制將數據存儲到多臺服務器,可以說是Redis集群;如果客戶端都是如Java沒什么問題,但是如果有多種類型客戶端(如PHP、C)等也要使用那么需要保證它們的分片邏輯是一樣的;另外隨著客戶端的增加,連接數也會隨之增多,發展到一定地步肯定會出現連接數不夠用的;此時Twemproxy就可以上場了。主要作用:分片、減少連接數。另外還提供了Hash Tag機制來幫助我們將相似的數據存儲到同一個分片。另外也可以參考豌豆莢的https://github.com/wandoulabs/codis。
?
基本配置
其使用YML語法,如
Java代碼??server1:是給當前分片配置起的名字,一個配置文件可以有多個分片配置;
listen?:?監聽的ip和端口;
hash:散列算法;
distribution:分片算法,比如一致性Hash/取模;
timeout:連接后端Redis或接收響應的超時時間;
redis:是否是redis代理,如果是false則是memcached代理;
servers:代理的服務器列表,該列表會使用distribution配置的分片算法進行分片;
?
分片算法
? hash算法:?
??? one_at_a_time
??? md5
??? crc16
??? crc32 (crc32 implementation compatible with?libmemcached)
??? crc32a (correct crc32 implementation as per the spec)
??? fnv1_64
??? fnv1a_64
??? fnv1_32
??? fnv1a_32
??? hsieh
??? murmur
??? jenkins
??分片算法:
??? ketama(一致性Hash算法)
??? modula(取模)
??? random(隨機算法)
?
服務器列表
? servers:
?? - ip:port:weight alias
如
? servers:
?? - 127.0.0.1:6660:1
? ?- 127.0.0.1:6661:1
或者
? servers:
?? - 127.0.0.1:6660:1 server1
?
? ?- 127.0.0.1:6661:1 server2
推薦使用后一種方式,默認情況下使用ip:port:weight進行散列并分片,這樣假設服務器宕機換上新的服務器,那么此時得到的散列值就不一樣了,因此建議給每個配置起一個別名來保證映射到自己想要的服務器。即如果不使用一致性Hash算法來作緩存服務器,而是作持久化存儲服務器時就更有必要了(即不存在服務器下線的情況,即使服務器ip:port不一樣但仍然要得到一樣的分片結果)。
?
HashTag
比如一個商品有:商品基本信息(p:id:)、商品介紹(d:id:)、顏色尺碼(c:id:)等,假設我們存儲時不采用HashTag將會導致這些數據不會存儲到一個分片,而是分散到多個分片,這樣獲取時將需要從多個分片獲取數據進行合并,無法進行mget;那么如果有了HashTag,那么可以使用“::”中間的數據做分片邏輯,這樣id一樣的將會分到一個分片。
?
nutcracker.yml配置如下
Java代碼???
連接Twemproxy
Java代碼???
在我的服務器上可以連接6660端口?
Java代碼???
一致性Hash與服務器宕機
如果我們把Redis服務器作為緩存服務器并使用一致性Hash進行分片,當有服務器宕機時需要自動從一致性Hash環上摘掉,或者其上線后自動加上,此時就需要如下配置:
?
#是否在節點故障無法響應時自動摘除該節點,如果作為存儲需要設置為為false
auto_eject_hosts: true
#重試時間(毫秒),重新連接一個臨時摘掉的故障節點的間隔,如果判斷節點正常會自動加到一致性Hash環上
server_retry_timeout: 30000
#節點故障無法響應多少次從一致性Hash環臨時摘掉它,默認是2
server_failure_limit: 2
?
支持的Redis命令
不是所有Redis命令都支持,請參考https://github.com/twitter/twemproxy/blob/master/notes/redis.md。
?
因為我們所有的Twemproxy配置文件規則都是一樣的,因此我們應該將其移到我們項目中。
Java代碼??另外Twemproxy提供了啟動/重啟/停止腳本方便操作,但是需要修改配置文件位置為/usr/example/nutcracker.yml。
Java代碼??將OPTIONS改為
OPTIONS="-d -c /usr/example/nutcracker.yml"
?
另外注釋掉. /etc/rc.d/init.d/functions;將daemon --user ${USER} ${prog} $OPTIONS改為${prog} $OPTIONS;將killproc改為killall。
?
這樣就可以使用如下腳本進行啟動、重啟、停止了。
/usr/servers/twemproxy-0.4.0/scripts/nutcracker.init {start|stop|status|restart|reload|condrestart}
?
對于擴容最簡單的辦法是:
1、創建新的集群;
2、雙寫兩個集群;
3、把數據從老集群遷移到新集群(不存在才設置值,防止覆蓋新的值);
4、復制速度要根據實際情況調整,不能影響老集群的性能;
5、切換到新集群即可,如果使用Twemproxy代理層的話,可以做到遷移對讀的應用透明。
來源:http://jinnianshilongnian.iteye.com/blog/2186787
總結
以上是生活随笔為你收集整理的第三章 Redis/SSDB+Twemproxy安装与使用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 第二章 OpenResty(Nginx+
- 下一篇: 第四章 Lua模块开发