REDIS: REmote DIctionary Server
下载
wget http://download.redis.io/releases/redis-3.0.3.tar.gz
git clone https://github.com/antirez/redis.git
编译安装
cd redis-3.0.3
make
sudo make install
启动停止
redis-server redis.conf
redis-cli -p 6379 shutdown / kill pid
配置文件
- daemonize yes
– port 6379
– logfile /home/redis/data_6379/redis.log
– pidfile /home/redis/data_6379/redis.pid
– maxmemory 2gb
– dbfilename dump.rdb
– dir /home/redis/data_6379/
– appendonly yes
– appendfsync everysec
采用type命令来查看数据类型
比如 apple:fru , banna:fru orange:fru
EXISTS
DEL
KEYS
EXPIRE / EXPIREAT / TTL / PERSIST
PEXPIRE / PEXPIREAT / PTTL
RENAME / RENAMENX
DUMP / RESTORE
MOVE / MIGRATE
GET / SET / SETEX / SETNX
MGET / MSET / MSETNX
APPEND
INCR / DECR / INCRBY / DECRBY / INCRBYFLOAT
GETBIT / SETBIT / BITCOUNT / BITOP
STRLEN
LPUSH / LPOP / LPUSHX / RPUSH / RPOP
BLPOP / BRPOP
LINSERT / LSET / LREM
LRANGE / LLEN
RPOPLPUSH / BRPOPLPUSH
SADD / SREM / SPOP / SMOVE
SISMEMBER / SMEMBERS / SRANDMEMBER
SCARD
SDIFF / SDIFFSTORE
SINTER / SINTERSTORE
SUNION / SUNIONSTORE
ZADD / ZREM
ZCOUNT / ZCARD
ZRANK / ZINCRBY / ZSCORE
案例:
各种系统中排名的存储
HSET / HGET / HMSET / HMGET / HDEL
HSETNX
HKEYS / HVALS / HGETALL
HINCRBY / HINCRBYFLOAT
HLEN
PFADD
PFCOUNT
PFMERGE
WATCH counter1 counter2
MULTI
INCR counter1
INCE counter2
EXEC
DISCARD
UNWATCH
节省流量
一个例子
用 Lua 脚本编程实现一个简单的转账的事务:
bob给 smith 转账了 20 块钱
EVAL "local a = redis.call('GET', 'bob:account');
local b = redis.call('GET', 'smith:account'); if not a
or not b then return 1 end; a = a - 20; b = b + 20; if
not redis.call('MSET', 'bob:account', a,
'smith:account', b) then return 2 end; return 0;" 0
上面的脚本存在问题
–因为一个交易,smith 需要给 bob 转 30 块钱
修改之后的脚本
EVAL "local a = redis.call('GET', KEYS[1]); local b =
redis.call('GET', KEYS[2]); if not a or not b then
return 1 end; if not redis.call('MSET', KEYS[1], a -
ARGV[1], KEYS[2], b + ARGV[1]) then return 2 end;
return 0;" 2 smith:account bob:account 30
上面转账的例子没有考虑到账户余额不足的情况
脚本经过 sha 编码之后的名字还是不容易记住,如何解决
脚本加载到缓存之后,如果 Redis 重启之后,脚本丢失,如何解决
文本持久化
Redis aof 持久化
为避免脚本中出现死循环,Redis 通过下面的配置
实现脚本执行超时控制
lua-time-limit
发布订阅(pub/sub)是一种消息通信方式 , 和消息队列类似
有两个角色执行不同的动作
发布订阅不涉及数据的存储,和 Redis 数据库
其他功能完全隔离
PUBLISH / SUBSCRIBE / UNSUBSCRIBE
PSUBSCRIBE / PUNSUBSCRIBE
PUBSUB
Redis 支持两种持久化方式
Snapshotting (default)
dump.rdb
AOF 方式
appendonly.aof
快照是默认的存储方式,这种方式是将内存中的数据以快照的方式写入到二进制文件中
触发条件
自动触发
save 900 1
save 300 10
save 60 10000
手动触发
原理
结束进程
注意事项
SAVE 命令的处理逻辑和上面不一样
阻塞式的——快照期间阻塞 client 请求
缺点
做快照需要时间,在做快照的过程中 Redis 做更改的那部分数据如何保证不丢失?
Append-Only File
配置文件开启,默认是关闭
appendfsync no
appendfsync everysec
appendfsync always
缺点
如何解决
注意:BGSAVE 和 BGREWRITEAOF 最好不要同时执行
Redis 灾难恢复
Redis 主从支持多种模式:M-S,S-M-S,M-S-S,据说支持 DAG!
启动一个 Redis 实例做为 Slave
在 Slave 实例上执行下面的命令
SLAVEOF Master_ip Master_port
实现1主1从结构
在 Slave 实例上执行下面的命令
SLAVEOF NO ONE
注意事项:
slave-buffer 大小的设定需要注意
INFO
DBSIZE
CONFIG SET / CONFIG GET
FLUSHDB / FLUSHALL
MONITOR / SLOWLOG GET / SLOWLOG SET
TIME / PING
CLIENT LIST / CLIENT KILL
SAVE / BGSAVE / BGREWRITESAVE / LASTSAVE
– SHUTDOWN
C: https://github.com/redis/hiredis
C++: https://github.com/jrk/redis-cplusplus-client
Java: https://github.com/xetorthio/jedis
Lua: https://github.com/nrk/redis-lua
Nodejs: https://github.com/fictorial/redis-node-client
Scala: https://github.com/top10/scala-redis-client
Php: https://github.com/nrk/phpiredis
Redis 高可用方案
适用于1主多从的情况,Master 挂掉,Sentinel负责从多个 Slave 中选出一个作为 Master,并将其他的 Slave 连上新的 Master
使用 Raft 选举算法:https://raft.github.io/
从 Redis3.0 开始支持
无中心,节点之间采用 gossip 协议传播信息
数据如何分片