上一章介绍了 RocksDB 的批量写入技术,以及如何将批量写入技术应用到缓存服务中。只需要改变rocksdbCache 结构体的内部实现,Set 操作就能有40%以上的写入性能提升。
那“如果 RocksDB 还支持批量读取,那我们的 Get 操作性能是否也可以得到提升?” 回答是:不行。RocksDB 虽然有一个批量读取 (MultiGet)功能,但是它不能让我们的读取性能得到提升。RocksDB的 MultiGet 无法提升读取性能的原因很简单:我们在第3章说过,RocksDB内部存储使用的是静态排序表 SST,而应用程序使用 MultiGet 读取的键不可能跟 SST中键的顺序保持一致,RocksDB 终究要去各个不同的 SST 表文件中查询每一个单独的键,这些键在 API 层面是否批量给出并没有太大区别。(批量写入之所以有效果是因为 RocksDB在写入的时候是不做排序直接写到 WAL日志里的另有线程在后台处理,将WAL合并到 SST 中。
异步操作能够提升读取性能的原理
在我们之前的实现中,服务端收到客户端的请求时,就会去调用 cache.Cache接口提供的方法并将结果返回给客户端。这是一种同步的操作,服务端在cache.Cache 的方法返回前都没有办法处理该 TCP 连接上的后续请求。这些后续请求会在服务端累积起来,等待服务,这样吞吐量就会下降。
异步操作是指当服务端收到请求时,它在一个新的goroutine里调用cache.Cache 方法,这样原来的 goroutine 就可以立即开始处理来自该TCP 连接的后续请求。
和批量写入会破坏数据的实时一致性和隐藏真实结果一样,使用异步操作也有它的代价,那就是额外的实现复杂度和时间开销。
本来我们的服务端的实现就是收到请求一-处理请求一一返回响应,所有操作同步进行,实现起来非常直观。