CRDT支持概述
CRDT天然支持redis的几种数据结构,下表给出一个简单映射:
redis数据结构 |
CRDT数据结构 |
string(int或double类型编码) |
counter |
string |
register |
set |
set |
基本kv |
set + register |
hash |
set + register |
zset |
set + register |
GEO |
set + register |
hyperloglog |
set |
然而对于redis来说,同一数据类型可能既存在CRDT中register的SET操作,又存在CRDT中counter的INCR操作。所以设计上我们考虑根据同一数据类型的不同命令划分命令集,不同命令集CRDT的实现方式不同。
CRDT支持原则
CRDT算法选择
- 若命令集内所有命令间均具备交换律、结合律的,直接回放操作(op-based CRDT)
- 若命令集对应的数据类型是set,使用基于时间戳做tag的OR-Set策略
- 其它情况使用LWW(Last write wins)策略
CRDT命令集
string
分为string,计数器(counter),位操作(bit)三类命令进行讨论
string
counter
bit
set
- CRDT典型使用场景: 购物车,收藏夹
-
保证命令集3: SADD
SREM
SPOP
- 暂不保证:
SMOVE
SINTERSTORE
SUNIONSTORE
SDIFFSTORE
hash
list
hyperloglog
- CRDT典型使用场景:统计全局的近似uv
-
保证命令集6:PFADD
- 暂不保证:
PFMERGE
- hll在redis中保存为string类型的对象, 所以原则上string类型的所有操作均可作用于hll之上, 但不建议对hll使用string类型的操作, 不仅保证不了最终一致, 还会破坏hll本身的正确性
zset
geo
- CRDT典型使用场景:全局地理位置信息
-
保证命令集9:GEOADD
- geo类型数据底层在redis中使用zset实现,所以原则上zset类型的所有操作均可作用于geo之上,但不建议对geo使用zset类型操作
其它redis特性支持
rdb
- 在rdb中保存crdt相关元信息,保证下次加载之后满足一致性,同时对开源redis 4.0及阿里云redis 4.0其它产品形态保持兼容
expire
- 对于expire的时间设置不保证最终一致,原则上以设置的最短过期时间为准,会分发DEL操作。
evict
- 内存处于高水位的特殊情况,直接根据具体设置策略逐出,目前不做最终一致保证
lua
实现代价
- 性能上无影响
- 每个key或field将多占用8个字节存储crdt相关元信息,未来可以压缩到4个字节
- set和hash类型只支持
OBJ_ENCODING_HT
编码,zset类型只支持 OBJ_ENCODING_SKIPLIST
编码,以下几个配置项将不再起作用:
set_max_intset_entries
hash_max_ziplist_entries
hash_max_ziplist_value
zset_max_ziplist_entries
zset_max_ziplist_value
- rdb将额外占用空间存储crdt元信息,但保证兼容性