Redis安裝與使用
1、下載redis並安裝
cd /usr/servers/
wget https://github.com/antirez/redis/archive/2.8.19.tar.gz
tar -xvf 2.8.19.tar.gz
cd redis-2.8.19/
make
2、後臺啓動Redis服務器
nohup /usr/servers/redis-2.8.19/src/redis-server /usr/servers/redis-2.8.19/redis.conf &
3、查看是否啓動成功
ps -aux | grep redis
4、進入客戶端
/usr/servers/redis-2.8.19/src/redis-cli -p 6379
5、執行如下命令
127.0.0.1:6379> set i 1
OK
127.0.0.1:6379> get i
"1"
通過如上命令可以看到我們的Redis安裝成功。更多細節請參考http://redis.io/。
Twemproxy安裝與使用
首先需要安裝autoconf、automake、libtool工具,比如ubuntu可以使用如下命令安裝
apt-get install autoconf automake
apt-get install libtool
1、下載Twemproxy並安裝
cd /usr/servers
wget https://github.com/twitter/twemproxy/archive/v0.4.0.tar.gz
tar -xvf v0.4.0.tar.gz
cd twemproxy-0.4.0/
autoreconf -fvi
./configure && make
此處根據要注意,如上安裝方式在有些服務器上可能在大量如mset時可能導致Twemproxy崩潰,需要使用如 CFLAGS=”-O1” ./configure && make或CFLAGS=”-O3 -fno-strict-aliasing” ./configure && make安裝。
2、配置
vim /usr/servers/twemproxy-0.4.0/conf/nutcracker.yml
server1:
listen: 127.0.0.1:1111
hash: fnv1a_64
distribution: ketama
redis: true
servers:
- 127.0.0.1:6379:1
3、啓動Twemproxy代理
/usr/servers/twemproxy-0.4.0/src/nutcracker -d -c /usr/servers/twemproxy-0.4.0/conf/nutcracker.yml
-d指定後臺啓動 -c指定配置文件;此處我們指定了代理端口爲1111,其他配置的含義後續介紹。
4、查看是否啓動成功
ps -aux | grep nutcracker
5、進入客戶端
/usr/servers/redis-2.8.19/src/redis-cli -p 1111
6、執行如下命令
127.0.0.1:1111> set i 1
OK
127.0.0.1:1111> get i
"1"
Twemproxy文檔請參考https://github.com/twitter/twemproxy。
安裝 centos
autoconf automake libtool
#whereis autoconf #查看autoconf的路徑
#rpm -qf /usr/bin/autoconf #查看autoconf的版本
#rpm -e --nodeps autoconf-2.59-12 #卸載原來版本
#tar -zxf autoconf-2.65.tar.gz
#cd autoconf-2.65
#./configure --prefix=/usr
#make && make install
#rpm -qf /usr/bin/autoconf
#rpm -qa | grep autoconf
#/usr/bin/autoconf --help
#/usr/bin/autoconf -V
Redis設置
基本設置
#端口設置,默認6379
port 6379
#日誌文件,默認/dev/null
logfile ""
Redis內存
內存大小對應關係
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes
#設置Redis佔用100mb的大小
maxmemory 100mb
#如果內存滿了就需要按照如相應算法進行刪除過期的/最老的
#volatile-lru 根據LRU算法移除設置了過期的key
#allkeys-lru 根據LRU算法移除任何key(包含那些未設置過期時間的key)
#volatile-random/allkeys->random 使用隨機算法而不是LRU進行刪除
#volatile-ttl 根據Time-To-Live移除即將過期的key
#noeviction 永不過期,而是報錯
maxmemory-policy volatile-lru
#Redis並不是真正的LRU/TTL,而是基於採樣進行移除的,即如採樣10個數據移除其中最老的/即將過期的
maxmemory-samples 10
而如Memcached是真正的LRU,此處要根據實際情況設置緩存策略,如緩存用戶數據時可能帶上了過期時間,此時採用volatile-lru即可;而假設我們的數據未設置過期時間,此時可以考慮使用allkeys-lru/allkeys->random;假設我們的數據不允許從內存刪除那就使用noeviction。
內存大小盡量在系統內存的60%~80%之間,因爲如客戶端、主從時複製時都需要緩存區的,這些也是耗費系統內存的。
Redis本身是單線程的,因此我們可以設置每個實例在6-8GB之間,通過啓動更多的實例提高吞吐量。如128GB的我們可以開啓8GB * 10個實例,充分利用多核CPU。
Redis主從
實際項目時,爲了提高吞吐量,我們使用主從策略,即數據寫到主Redis,讀的時候從從Redis上讀,這樣可以通過掛載更多的從來提高吞吐量。而且可以通過主從機制,在葉子節點開啓持久化方式防止數據丟失。
#在配置文件中掛載主從,不推薦這種方式,我們實際應用時Redis可能是會宕機的
slaveof masterIP masterPort
#從是否只讀,默認yes
slave-read-only yes
#當從失去與主的連接或者複製正在進行時,從是響應客戶端(可能返回過期的數據)還是返回“SYNC with master in progress”錯誤,默認yes響應客戶端
slave-serve-stale-data yes
#從庫按照默認10s的週期向主庫發送PING測試連通性
repl-ping-slave-period 10
#設置複製超時時間(SYNC期間批量I/O傳輸、PING的超時時間),確保此值大於repl-ping-slave-period
#repl-timeout 60
#當從斷開與主的連接時的複製緩存區,僅當第一個從斷開時創建一個,緩存區越大從斷開的時間可以持續越長
# repl-backlog-size 1mb
#當從與主斷開持續多久時清空複製緩存區,此時從就需要全量複製了,如果設置爲0將永不清空
# repl-backlog-ttl 3600
#slave客戶端緩存區,如果緩存區超過256mb將直接斷開與從的連接,如果持續60秒超過64mb也會斷開與從的連接
client-output-buffer-limit slave 256mb 64mb 60
主從示例
cd /usr/servers/redis-2.8.19
cp redis.conf redis_6660.conf
cp redis.conf redis_6661.conf
vim redis_6660.conf
vim redis_6661.conf
將端口分別改爲port 6660和port 6661,然後啓動
nohup /usr/servers/redis-2.8.19/src/redis-server /usr/servers/redis-2.8.19/redis_6660.conf &
nohup /usr/servers/redis-2.8.19/src/redis-server /usr/servers/redis-2.8.19/redis_6661.conf &
查看是否啓動
ps -aux | grep redis
進入從客戶端,掛主
/usr/servers/redis-2.8.19/src/redis-cli -p 6661
127.0.0.1:6661> slaveof 127.0.0.1 6660
OK
127.0.0.1:6661> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6660
master_link_status:up
master_last_io_seconds_ago:3
master_sync_in_progress:0
slave_repl_offset:57
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
進入主
/usr/servers/redis-2.8.19# /usr/servers/redis-2.8.19/src/redis-cli -p 6660
127.0.0.1:6660> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=127.0.0.1,port=6661,state=online,offset=85,lag=1
master_repl_offset:85
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:84
127.0.0.1:6660> set i 1
OK
進入從
/usr/servers/redis-2.8.19/src/redis-cli -p 6661
127.0.0.1:6661> get i
"1"
此時可以看到主從掛載成功,可以進行主從複製了。使用slaveof no one斷開主從。
Redis持久化
Redis雖然不適合做持久化存儲,但是爲了防止數據丟失有時需要進行持久化存儲,此時可以掛載一個從(葉子節點)只進行持久化存儲工作,這樣假設其他服務器掛了,我們可以通過這個節點進行數據恢復。
Redis持久化有RDB快照模式和AOF追加模式,根據自己需求進行選擇。
RDB持久化
#格式save seconds changes 即N秒變更N次則保存,從如下默認配置可以看到丟失數據的週期很長,通過save “” 配置可以完全禁用此持久化
save 900 1
save 300 10
save 60 10000
#RDB是否進行壓縮,壓縮耗CPU但是可以減少存儲大小
rdbcompression yes
#RDB保存的位置,默認當前位置
dir ./
#RDB保存的數據庫名稱
dbfilename dump.rdb
#不使用AOF模式,即RDB模式
appendonly no
可以通過set一個數據,然後很快的kill掉redis進程然後再啓動會發現數據丟失了。
AOF持久化
AOF(append only file)即文件追加模式,即把每一個用戶操作的命令保存下來,這樣就會存在好多重複的命令導致恢復時間過長,那麼可以通過相應的配置定期進行AOF重寫來減少重複。
#開啓AOF
appendonly yes
#AOF保存的位置,默認當前位置
dir ./
#AOF保存的數據庫名稱
appendfilename appendonly.aof
#持久化策略,默認每秒fsync一次,也可以選擇always即每次操作都進行持久化,或者no表示不進行持久化而是藉助操作系統的同步將緩存區數據寫到磁盤
appendfsync everysec
#AOF重寫策略(同時滿足如下兩個策略進行重寫)
#當AOF文件大小佔到初始文件大小的多少百分比時進行重寫
auto-aof-rewrite-percentage 100
#觸發重寫的最小文件大小
auto-aof-rewrite-min-size 64mb
#爲減少磁盤操作,暫緩重寫階段的磁盤同步
no-appendfsync-on-rewrite no
此處的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)
127.0.0.1:6660> config get maxmemory
1) "maxmemory"
2) "10485760"
設置新的maxmemory(20mb)
127.0.0.1:6660> config set maxmemory 20971520
OK
但是此時重啓redis後該配置會丟失,可以執行如下命令重寫配置文件
127.0.0.1:6660> config rewrite
OK
注意:此時所有配置包括主從配置都會重寫
Redis執行Lua腳本
Redis客戶端支持解析和處理lua腳本,因爲Redis的單線程機制,我們可以藉助Lua腳本實現一些原子操作,如扣減庫存/紅包之類的。此處不建議使用EVAL直接發送lua腳本到客戶端,因爲其每次都會進行Lua腳本的解析,而是使用SCRIPT LOAD+ EVALSHA進行操作。未來不知道是否會用luajit來代替lua,讓redis lua腳本性能更強。
Twemproxy設置
一旦涉及到一臺物理機無法存儲的情況就需要考慮使用分片機制將數據存儲到多臺服務器,可以說是Redis集羣;如果客戶端都是如Java沒什麼問題,但是如果有多種類型客戶端(如PHP、C)等也要使用那麼需要保證它們的分片邏輯是一樣的;另外隨着客戶端的增加,連接數也會隨之增多,發展到一定地步肯定會出現連接數不夠用的;此時Twemproxy就可以上場了。主要作用:分片、減少連接數。另外還提供了Hash Tag機制來幫助我們將相似的數據存儲到同一個分片。另外也可以參考豌豆莢的https://github.com/wandoulabs/codis。
基本配置
其使用YML語法,如
server1:
listen: 127.0.0.1:1111
hash: fnv1a_64
distribution: ketama
timeout:1000
redis: true
servers:
- 127.0.0.1:6660:1
- 127.0.0.1:6661:1
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配置如下
server1:
listen: 127.0.0.1:1111
hash: fnv1a_64
distribution: ketama
redis: true
hash_tag: "::"
servers:
- 127.0.0.1:6660:1 server1
- 127.0.0.1:6661:1 server2
連接Twemproxy
/usr/servers/redis-2.8.19/src/redis-cli -p 1111
127.0.0.1:1111> set p:12: 1
OK
127.0.0.1:1111> set d:12: 1
OK
127.0.0.1:1111> set c:12: 1
OK
在我的服務器上可以連接6660端口
/usr/servers/redis-2.8.19/src/redis-cli -p 6660
127.0.0.1:6660> get p:12:
"1"
127.0.0.1:6660> get d:12:
"1"
127.0.0.1:6660> get c:12:
"1"
一致性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配置文件規則都是一樣的,因此我們應該將其移到我們項目中。
cp /usr/servers/twemproxy-0.4.0/conf/nutcracker.yml /usr/example/
另外Twemproxy提供了啓動/重啓/停止腳本方便操作,但是需要修改配置文件位置爲/usr/example/nutcracker.yml。
chmod +x /usr/servers/twemproxy-0.4.0/scripts/nutcracker.init
vim /usr/servers/twemproxy-0.4.0/scripts/nutcracker.init
對於擴容最簡單的辦法是:
1、創建新的集羣;
2、雙寫兩個集羣;
3、把數據從老集羣遷移到新集羣(不存在才設置值,防止覆蓋新的值);
4、複製速度要根據實際情況調整,不能影響老集羣的性能;
5、切換到新集羣即可,如果使用Twemproxy代理層的話,可以做到遷移對讀的應用透明。