sleeprite / rudis

Rudis is a high-performance in memory database
https://sleeprite.github.io/rudis/
GNU General Public License v3.0
239 stars 28 forks source link

关于线程模型 #3

Closed songzhi closed 2 months ago

songzhi commented 3 months ago

我观察到目前的线程模型是 shared-everything,每处理一个请求就要拿全局锁,并且直到请求执行完成才释放。

这样有几个缺点:

  1. 并发请求被迫串行化,这甚至比 Redis 官方实现的还要糟,后者可以在单线程内任意并发。
  2. 如果多个并发请求分别由几个线程进行处理,不同线程访问同一块内存,即使有锁保证正确性,也对 cpu 缓存不友好,会造成cache thrashing。

我的建议: 线程模型改为 shared-nothing,一个 database 的所有访问请求只能在同一个线程被处理,也就是说 Database: !Send。网络连接则可以在线程间任意传递,处理请求时只要通过消息传递转发到对应的 database 就行。不同的 database 可以处于不同的线程,以实现扩展性,后期还可以提供自动 sharding 的中间件。

sleeprite commented 3 months ago

这也是我最近迫切希望解决的问题,有很多方案也在积极探索中,感谢你的提案。

我理解你的建议是降低锁的粒度,将 db 的实例锁,下放一层,到具体的 db,减少锁资源的竞争。

如果这样的话,对于不同 db 的不同数据结构上锁,似乎可以进一步提高性能,但终究都会有上锁和释放锁的性能损耗。除此之外,rudis 是否可以使用无锁编程等方式,能有更多的提升空间。

另外,我也在考虑 rwlock 是否能代替 m 锁,在读的工作上避免锁的存在,对此你有什么好的建议

songzhi commented 2 months ago

不需要锁,网络请求通过消息传递传给某个 database 的 worker,而这个 worker 因为不会跨线程工作,所以 database 内的所有数据结构都可以是线程不安全的。这种线程模型就是 Redis 官方的线程模型,Redis 只在网络请求处理部分做了多线程,核心数据结构还是单线程的。这样做的性能是最好的,只是扩展性不够,这个问题可以通过 sharding 的方式解决。无锁数据结构并不是免费的午餐,理论上性能最好的方式就是避免任何CPU核间通讯。

sleeprite commented 2 months ago

不需要锁,网络请求通过消息传递传给某个 database 的 worker,而这个 worker 因为不会跨线程工作,所以 database 内的所有数据结构都可以是线程不安全的。这种线程模型就是 Redis 官方的线程模型,Redis 只在网络请求处理部分做了多线程,核心数据结构还是单线程的。这样做的性能是最好的,只是扩展性不够,这个问题可以通过 sharding 的方式解决。无锁数据结构并不是免费的午餐,理论上性能最好的方式就是避免任何CPU核间通讯。

再次感谢你的提案,并给出了耐心的解释,未来几个版本我们将针对代码进行进一步的调整,如果你对此也有兴趣,也欢迎你的加入 >_<

acking-you commented 2 months ago

这方面可以不要用 tokio,改用 monoio 解决,当然我觉得最大的问题可能不是这个,我觉得可能是代码质量和代码风格以及模块拆分的一点也不 rust,很多可以 zero cost 实现的部分都感觉在写 Java,作为玩具来开发的话感觉挺好,但是如果作为真正想落地生产的项目,太欠火候了(就算再多人参与,这基础的框子没搭好,后续也很难维护)...... 总的来看,可能作者刚写 rust 没多久,丧失很多的性能敏感的 sense

sleeprite commented 2 months ago

很多可以 zero cost 实现的部分都感觉在写 Java

评价的很到位,我是一个 5 年 java,偶尔写写 js,所以在 rust 的编码上有一些其他语言的习惯,但是有用心写,命令的扩展上也有考虑到,可能实现上有一股 java 味,你可以提供一些参考性的建议,帮助我们来改进它。

此外,我近期看下你提到的 monoio,看看能否有些启发

acking-you commented 2 months ago

很多可以 zero cost 实现的部分都感觉在写 Java

评价的很到位,我是一个 5 年 java,偶尔写写 js,所以在 rust 的编码上有一些其他语言的习惯,但是有用心写,命令的扩展上也有考虑到,可能实现上有一股 java 味,你可以提供一些参考性的建议,帮助我们来改进它。

此外,我近期看下你提到的 monoio,看看能否有些启发

代码风格也应该规范一下,比如 cargo clippy 至少得过吧

sleeprite commented 2 months ago

很多可以 zero cost 实现的部分都感觉在写 Java

评价的很到位,我是一个 5 年 java,偶尔写写 js,所以在 rust 的编码上有一些其他语言的习惯,但是有用心写,命令的扩展上也有考虑到,可能实现上有一股 java 味,你可以提供一些参考性的建议,帮助我们来改进它。 此外,我近期看下你提到的 monoio,看看能否有些启发

代码风格也应该规范一下,比如 cargo clippy 至少得过吧

我正在 dev 陆续调整 https://github.com/sleeprite/rudis/commit/6e3f55c61ac0905cfb1b760e8107503a8fa13342

sleeprite commented 2 months ago

很多可以 zero cost 实现的部分都感觉在写 Java

评价的很到位,我是一个 5 年 java,偶尔写写 js,所以在 rust 的编码上有一些其他语言的习惯,但是有用心写,命令的扩展上也有考虑到,可能实现上有一股 java 味,你可以提供一些参考性的建议,帮助我们来改进它。 此外,我近期看下你提到的 monoio,看看能否有些启发

代码风格也应该规范一下,比如 cargo clippy 至少得过吧

dev 已经通过 clippy 编译啦,仅剩一个 warning:Finished dev [unoptimized + debuginfo] target(s) in 0.42s

acking-you commented 2 months ago

很多可以 zero cost 实现的部分都感觉在写 Java

评价的很到位,我是一个 5 年 java,偶尔写写 js,所以在 rust 的编码上有一些其他语言的习惯,但是有用心写,命令的扩展上也有考虑到,可能实现上有一股 java 味,你可以提供一些参考性的建议,帮助我们来改进它。 此外,我近期看下你提到的 monoio,看看能否有些启发

代码风格也应该规范一下,比如 cargo clippy 至少得过吧

dev 已经通过 clippy 编译啦,仅剩一个 warning:Finished dev [unoptimized + debuginfo] target(s) in 0.42s

一个可持续发展的 rust 项目,应该至少添加一些常见的 clippy 规则来规范代码注释以及规范的编写(虽然一般根据不同项目开启的严格程度不同,见过最严格的会开到整数加法都会检查溢出,但最基本的注释没见过哪个项目是没有开的)

一般这三个是最基本的

![doc = include_str!("../README.md")]

![deny(missing_docs, rustdoc::broken_intra_doc_links)]

![cfg_attr(docsrs, feature(doc_auto_cfg))]

sleeprite commented 2 months ago

很多可以 zero cost 实现的部分都感觉在写 Java

评价的很到位,我是一个 5 年 java,偶尔写写 js,所以在 rust 的编码上有一些其他语言的习惯,但是有用心写,命令的扩展上也有考虑到,可能实现上有一股 java 味,你可以提供一些参考性的建议,帮助我们来改进它。 此外,我近期看下你提到的 monoio,看看能否有些启发

代码风格也应该规范一下,比如 cargo clippy 至少得过吧

dev 已经通过 clippy 编译啦,仅剩一个 warning:Finished dev [unoptimized + debuginfo] target(s) in 0.42s

一个可持续发展的 rust 项目,应该至少添加一些常见的 clippy 规则来规范代码注释以及规范的编写(虽然一般根据不同项目开启的严格程度不同,见过最严格的会开到整数加法都会检查溢出,但最基本的注释没见过哪个项目是没有开的)

一般这三个是最基本的 #![doc = include_str!("../README.md")] #![deny(missing_docs, rustdoc::broken_intra_doc_links)] #![cfg_attr(docsrs, feature(doc_auto_cfg))]

你是否可以帮助我们来构建这套规则体系,如果可以感谢你的帮助

acking-you commented 2 months ago

很多可以 zero cost 实现的部分都感觉在写 Java

评价的很到位,我是一个 5 年 java,偶尔写写 js,所以在 rust 的编码上有一些其他语言的习惯,但是有用心写,命令的扩展上也有考虑到,可能实现上有一股 java 味,你可以提供一些参考性的建议,帮助我们来改进它。 此外,我近期看下你提到的 monoio,看看能否有些启发

代码风格也应该规范一下,比如 cargo clippy 至少得过吧

dev 已经通过 clippy 编译啦,仅剩一个 warning:Finished dev [unoptimized + debuginfo] target(s) in 0.42s

一个可持续发展的 rust 项目,应该至少添加一些常见的 clippy 规则来规范代码注释以及规范的编写(虽然一般根据不同项目开启的严格程度不同,见过最严格的会开到整数加法都会检查溢出,但最基本的注释没见过哪个项目是没有开的) 一般这三个是最基本的 #![doc = include_str!("../README.md")] #![deny(missing_docs, rustdoc::broken_intra_doc_links)] #![cfg_attr(docsrs, feature(doc_auto_cfg))]

你是否可以帮助我们来构建这套规则体系,如果可以感谢你的帮助

闲暇时间我也想搞搞,但应该很难闲下来😭