Dawn's Blogs

分享技术 记录成长

0%

Simple-Redis实现 (13) 总结

本项目完整地址 simple-redis

总结

功能实现

Simple-Redis 是一个 golang 编写的实现了 RESP(REdis Serialization Protocol)协议的简易 Redis,实现的功能包括:

  • 五大基本数据类型(string、set、hash、list、zset)及其操作。
  • 通信协议为 RESP 协议,与 Redis-cli 兼容。
  • 增加并发性,可以并发执行命令。
  • AOF 持久化功能,包括 AOF 持久化和 AOF 重写。
  • 分片集群功能,以一致性哈希实现。
  • 发布订阅功能,更支持集群下的发布订阅模式。
  • 支持原子事务,在执行错误时进行回滚。
  • 支持分布式事务,支持在多集群下的 TCC 分布式事务。

优势

相比于 Redis,Simple-Redis 的优势在于:

  • 与 Redis 在执行命令时单线程不同,Simple-Redis 为每一个客户端并发的执行命令
  • pipeline 模式客户端,无需等待响应即可发送下一条命令。
  • TTL 过期使用时间轮算法实现,时间轮算法保证了不会扫描全部的 key(节省 CPU),又能够及时的删除过期数据(节省 内存)
  • 集群采用一致性哈希实现,使 key 更加均匀的分布。
  • 集群间的通信采用连接池的方式,优势在于:
    • 复用连接(复用空闲连接)。
    • 增加并发性能(节点之间有多个连接)。
    • 控制节点之间的连接数,不会因为节点之间的通信而影响客户端与节点之间的通信(有最大空闲连接数和最大活跃连接数的限制)。
  • 支持集群下的发布订阅模式,为了支持这一功能,定义了 publish 和 publishsingle 命令。
    • publish 命令:客户端向集群中的一个节点发送 publish 命令,节点会向所有的 peers 转发这条发布消息
    • publishsingle 命令:节点向所有 peers 转发发布的消息时,使用的是 publishsingle 命令,表明节点在收到消息后不用继续转发了(避免了节点转发再转发,造成的无限消息洪泛)。
  • 支持原子事务,在执行错误时进行回滚。
  • 支持分布式事务,支持在多集群下的 TCC 分布式事务。以当前节点为事务协调者,控制分布在其他节点的本地事务。一次分布式事务的流程如下:
    • 对命令和 watch 的 key,按照节点的不同进行分组
    • 对每一组节点发送 try 命令,try 命令比较复杂又分为几个子命令:
      • try start:通知节点有新建一个本地分布式事务。
      • try watched:发送 wath 时的 version,比较 version 是否发生变化。
      • try xxx:依次发送在该节点上执行的命令。
      • try end:通知 try 阶段已经结束,本地事务检查版本是否变化、锁定相关的 key。
    • 对每一组节点发送 commit 或者 cancel 命令
    • 重组事务的返回结果,按照正常的顺序进行返回。

性能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
zhaohan08@MacBook-Pro redis % redis-benchmark -t set,get,incr,lpush,rpush,lpop,rpop,sadd,hset,spop,zadd,lrange -n 10000 -q
WARNING: Could not fetch server CONFIG
SET: 68965.52 requests per second, p50=0.367 msec
GET: 62111.80 requests per second, p50=0.399 msec
INCR: 49751.24 requests per second, p50=0.487 msec
LPUSH: 56497.18 requests per second, p50=0.447 msec
RPUSH: 49504.95 requests per second, p50=0.503 msec
LPOP: 68965.52 requests per second, p50=0.375 msec
RPOP: 68493.15 requests per second, p50=0.375 msec
SADD: 52631.58 requests per second, p50=0.495 msec
HSET: 68027.21 requests per second, p50=0.375 msec
SPOP: 68027.21 requests per second, p50=0.383 msec
ZADD: 49751.24 requests per second, p50=0.503 msec
LPUSH (needed to benchmark LRANGE): 56818.18 requests per second, p50=0.463 msec
LRANGE_100 (first 100 elements): 25773.20 requests per second, p50=0.895 msec
LRANGE_300 (first 300 elements): 13586.96 requests per second, p50=1.775 msec
LRANGE_500 (first 500 elements): 9041.59 requests per second, p50=2.607 msec
LRANGE_600 (first 600 elements): 7704.16 requests per second, p50=3.015 msec

在单机时,可以得出结论,Simple-Redis 和 Redis 是有性能差距的(达到 Redis 的 60-70%),具体数据如下:

  • string 类型:Simple-Redis 的性能大约是 Redis 的 70%。
  • list 类型:Simple-Redis 的性能大约是 Redis 的 50%。
  • hash 类型:Simple-Redis 大约是 Redis 的 75%。
  • set 类型:Simple-Redis 的性能大约是 Redis 的 55%。
  • zset 类型:Simple-Redis 的性能大约是 Redis 的 50%。