Skip to content

asyncins/medis

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Medis 高性能的全局唯一 ID 发号服务

Medis 是薄雾算法 Mist 的工程实践,其名取自 Mist 和 Redis。薄雾算法是一款性能强到令我惊喜的全局唯一 ID 算法,我将它与业内同样高性能的 Redis 和 Golang 结合到一起,碰撞出了 TPS 为 2.5w/sec 这样超高性能的工程。

有了 Mist 和 Medis,你就拥有了和美团 Leaf微信 Seqsvr百度 UIDGenerator 性能相当(甚至超过)的全局唯一 ID 服务了。相比复杂的 UIDGenerator 双 Buffer 优化和 Leaf-Snowflake,薄雾算法 Mist 简单太多了。

分布式环境下的 CAP 选择?

你可以基于 Mist 算法打造一个 CP 或者 AP 的分布式服务架构,因为 Mist 足够简单,你只需要专心设计 CAP 的取舍即可。

无数的架构师说过,分布式环境下的服务,简单即是强

Medis 的性能测试

选用 Jmeter 作为性能测试工具,测试参数:1 秒内启动100 并发无限循环,即

Number of Threads  100
Ramp-up period     1
Loop Count         Infinte    

在 Jmeter 测试的同时,我还用 Gorouting * 10 开启了对数据正确性的测试,数据正确无误;

小数值(十万级)测试会导致频繁的预读预写 Redis 和 Channel,性能约为 2w/sec TPS

大数值(百万级)测试贴近真是业务环境,以下是 Channel 容量为 500W 时的测试结果

Samples Average Median 90% Line 95% Line 99% Line Throughput
30000000 3 2 4 6 12 27070/sec
50000000 4 3 7 10 21 22369/sec

Medis 的高性能从何而来?

作为开发者,你一定想知道 Medis 这 2.5w/sec 的 TPS 到底从何而来。实际上这不仅是薄雾算法本身超高性能带来的结果,我在设计上也做了很多尝试,例如:

  • 使用 Channel 作为数据缓存,这个操作使得发号服务性能提升了 7 倍;
  • 采用预存预取的策略保证 Channel 在大多数情况下都有值,从而能够迅速响应客户端发来的请求;
  • Gorouting 去执行耗费时间的预存预取操作,不会影响对客户端请求的响应;
  • 采用 Lrange Ltrim 组合从 Redis 中批量取值,这比循环单次读取或者管道批量读取的效率更高;
  • 写入 Redis 时采用管道批量写入,效率比循环单次写入更高;
  • Seqence 值的计算在预存前进行,这样就不会耽误对客户端请求的响应,虽然薄雾算法的性能是纳秒级别,但并发高的时候也造成一些性能损耗,放在预存时计算显然更香;
  • 得益于 Golang Echo 框架和 Golang 本身的高性能,整套流程下来我很满意,如果要追求极致性能,我推荐大家试试 Rust;

预存预取是什么流程?

预存预取是 Medis 高性能的基础之一,待我补充流程图。

致谢

谢谢 @青南 在 Redis 读取环节提供的 Lrange Ltrim 建议,我替换掉了循环 RPOP 操作,这使得读性能飙升;

谢谢 @Manjusaka@夏溪辰 在 Gorouting 触发环节提供的全局变量和定时器建议,这里选用了全局变量锁定 Gorouting,效果相当好;

谢谢 @夜幕团队 @崔庆才 @大鱼 @Loco 在性能测试和 Golang 方面的建议;

About

麦迪斯,一款基于 Golang Redis 和 Mist 算法的超高性能全局唯一 ID 发号服务

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages