部署模式
主从
一主多从,主节点负责写入,从节点负责复制。但并非高可用,主节点挂了,要人工切换。
哨兵
Redis 的哨兵模式是为了解决主从模式的高可用方案。
其引入了一个 Sentinel 系统去监视主节点及其从节点。一旦发现有主节点宕机后,会自动选举其中的一个从节点升级为新的主节点以达到故障转移的目的。
同样的, Sentinel 系统也需要达到高可用,所以一般也是集群,互相之间也会监控。
cluster
哨兵模式实现了高可用,读写分离,但是其主节点仍然只有一个,即写入操作都是在主节点中,这也成为了性能瓶颈。
cluster会由多个主节点组成,每个节点都是互相连接的,会保存自己与其他节点的信息。节点之间通过 gossip 协议交换互相的状态,以及新加入的节点信息。
Redis Cluster 的整个数据库将会被分为 16384个哈希slot,数据库中的每个键都属于这 16384 个slot中的其中一个,集群中的每个节点可以保存部分slot。其实就是sharding。
Redis cluster的一些要点:
- Redis Cluster中节点负责存储数据,记录集群状态,集群节点能自动发现其他节点,检测出节点的状态,并在需要时剔除故障节点,选举新的主节点
- 客户端和集群中的节点直连,不需要中间的Proxy层。理论上而言,客户端可以自由地向集群中的所有节点发送请求,但是每次不需要连接集群中的所有节点,只需要连接集群中任何一个可用节点即可。当客户端发起请求后,接收到重定向(MOVED\ASK)错误,会自动重定向到其他节点,所以客户端无需保存集群状态。不过客户端可以缓存键值和节点之间的映射关系,这样能明显提高命令执行的效率。
- Redis Cluster中节点之间使用异步复制,在分区过程中存在窗口,容易导致丢失写入的数据
- Redis Cluster中所有节点通过PING-PONG机制彼此互联,使用一个二级制协议(Cluster Bus) 进行通信,优化传输速度和带宽。发现新的节点、发送PING包、特定情况下发送集群消息,集群连接能够发布与订阅消息。
- 每个主节点可以有一个到N个从节点(Slave),当主节点出现宕机或网络断线等不可用时,从节点能自动提升为主节点进行处理
pub/sub
发布消息:
publish channel msg
订阅消息
subscribe channel1 channel2 …
模式匹配的方式订阅
psubscribe pattern1 pattern2 …
实时性
redis的pubsub实现很高效,似乎是实时的:
Redis effectively implements the Pub/Sub model allowing throughput of up to 1 million messages per second
阻塞问题
基于jedis connection的subscribe 会阻塞住调用线程,而基于lettuce connection的则不会。这点差异在编码时要特别注意。
key变更事件
notify-keyspace-events
notify-keyspace-events 的参数为 “Ex”。x 代表了过期事件
所有配置:
K:Keyspace事件,将会以__keyspace@<db>__作为事件的前缀
E:Keyevent事件,将会以__keyevent@<db>__作为事件的前缀g:非特定类型的通用命令,例如DEL、EXPIRE、RENAME等
$:字符串命令,例如SET、INCR等
l:列表命令,例如LPUSH、LPOP等
s:集合命令,例如SADD、SREM等
h:哈希表命令,例如HSET、HINCRBY等
z:有序集合命令,例如ZSET、ZREM等
t:流命令,例如XADD、XDEL等
x:过期事件(在每个键过期的时侯产生)
e:淘汰事件(在每个键被淘汰的时候产生)
m:未命中事件(在访问某个不存在的键使产生)
A:配置g$lshztxe的别名,但不包括未命中事件m
集群里的keyspace事件
Every node of a Redis cluster generates events about its own subset of the keyspace as described above. However, unlike regular Pub/Sub communication in a cluster, events' notifications are not broadcasted to all nodes(这里的言外之意,pubsub会广播到所有节点,事件则不会). Put differently, keyspace events are node-specific. This means that to receive all keyspace events of a cluster, clients need to subscribe to each of the nodes.
来源参考:
https://redis.io/docs/manual/keyspace-notifications/
使用lettuce的Cluster API也可以处理集群事件:
redis Cluster also makes a distinction between user-space and key-space messages. Key-space notifications (Pub/Sub messages for key-activity) stay node-local and are not broadcasted across the Redis Cluster. A notification about, e.g. an expiring key, stays local to the node on which the key expired.Clients that are interested in keyspace notifications must subscribe to the appropriate node (or nodes) to receive these notifications. You can either use RedisClient.connectPubSub() to establish Pub/Sub connections to the individual nodes or use RedisClusterClient's message propagation and NodeSelection API to get a managed set of connections.
参见:
https://blog.csdn.net/iverson2010112228/article/details/115873264
key过期事件的实时性问题
redis的key过期机制在时间上很不准,因为它要么访问key时检查超时,要么后台定期抽样检查超时,一旦超时key很多,处理不过来,超时时间很大概率是不准的。
对于需要精确超时的场景(例如心跳),redis的key过期机制不能用的。
pipeline
注意:Pipeline 是非原子的 ,且每次只能作用在一个 Redis 节点上。
cluster要支持pipeline,需自己写代码支持,参考:
https://www.jianshu.com/p/8f53ac71a552
cluster下lua脚本的执行
如果lua脚本操作多个key,可能会报crossslot错误,导致lua脚本无法执行。
但可以通过在key中设置{},强行把key放一个slot里,再用lua执行。