ebpf-cache-for-redis
ebpf-cache-for-redis copied to clipboard
Inkernel cache for Redis that serves requests before the execution of the standard network stack.
any benchmark?
这个项目我认为最好的结果是去提供一个通用的协议解析层,使得用户可以基于我们提供的接口自己实现一个协议的解析,并直接对接数据传入和传出,相当于整个逻辑划分为两个板块,一个是协议解析,一个是数据处理。 这其实类似于大多数多模型数据库的做法,即在计算层先转化其他模型为KV,然后在存储层可以封装复杂性,提供kv接口就可以了,更细节的,其实在计算层中不同的协议解析都是不同的类。 类比到brc来其实就是,协议解析层是不同的bpf函数,要添加一个新的协议解析只需要加一个新的bpf函数,放到整个尾调用链中来就可以了(这里有两个问题,首先不一定是尾调用链,也可以是bpf to bpf call;其次单个bpf函数可能不足以承载协议解析的复杂性,整个后续遇到再解决) 这就是我想做成的样子。
这个需要看一下用到的helper和MAP结构的支持版本,需要点时间做一下,以提升用户体验。 未完成。
目前使用的MAP类型是BPF_MAP_TYPE_ARRAY,原因见 https://blog.csdn.net/weixin_43705457/article/details/123569330 这意味着key/value限制实际上是固定的,所以key/value的大小会有限制,大于MAP初始化时候设置的限制只能pass到用户态处理;而且会导致大量的内存碎片,比如说目前value设置硬限制为1024字节,如果大量的value都是1字节,基本所有的内存都被浪费掉了。 这里我的解决方案是仿照redis中数据结构升级的做法,但不是完全仿照,即设置一个BPF_MAP_TYPE_ARRAY,value设置的非常大,在value之上构建[listpack](https://blog.csdn.net/weixin_43705457/article/details/117906138)。 redis最新版本的实现是哈希表在数据较少时为listpack([redis7.0特性](https://raw.githubusercontent.com/redis/redis/7.0/00-RELEASENOTES),以前是ziplist,替换 ziplist 为 listpack 在Hash, List, Zset结构中的PR是 #8887, #9366, #9740),较大时为哈希表。 如此可以解决大小限制问题与内存碎片问题,但是实际的查询时间复杂度会降低,而且此时的内存淘汰策略需要讨论。 未实现。
### 鉴权 我们可以复用用户态AUTH的语意,然后把用户本身和五元组做一个绑定,在AUTH的时候做映射,在读请求来的时候拒绝没有AUTH的五元组,写请求直接pass到用户态就可以。 ### 多租户隔离 多租户隔离对于数据库的实际的运行成本来说是非常重要的,可以说数据隔离的粒度决定相关产品技术栈的深度,经典的隔离粒度有database隔离,schema隔离,partition隔离,partition共享等。 我们希望做到在内核中可以做到多租户之间不可见(其实从隔离粒度来讲就是partition共享),但是首先需要标识用户这个概念,目前[ebpf-cache-for-redis](https://github.com/Super-long/ebpf-cache-for-redis)是没有连接这个概念的,只是在TC ingress/egress 中捕获语句而已。 我们可以结合鉴权,捕获AUTH命令(注意AUTH命令的两种格式)做一个五元组到用户的映射,并在每一个数据项上标识用户,在数据读操作时做判断(原因是读操作会直接在内核处理返回,写操作都是pass到用户态的),看数据是否属于该用户。 未实现。
目前ebpf-cache-for-redis中的BPF程序都是object-pin在bpf文件系统中的,也就是说这MAP中缓存的数据其实和用户态是重复的,但是这个问题并不简单。 因为ebpf-cache-for-redis我们希望其对用户态程序的影响可以是零,即需要加速时挂载,不需要时直接卸载,用户态仍旧可以继续处理,且没有任何一致性问题,目前的做法是写操作pass到用户态处理,读操作ingress可以直接返回,egress负责更新cache。 所以能否可以在内核态劫持写操作,不pass到用户态,并对这部分语句做一个记录,在ebpf卸载时把这部分语句统一返回到用户态处理,最大程度保证一致性呢。 这里有两个问题: 1. 即redis的持久性变的更差了,可能丢失的数据变的更多了,但是同样的带来了极致的内存利用率和性能,这是一个对某些业务来说有极强吸引力的功能。 2. 这部分数据在用户态重放时失败怎么办?这要求我们需要划定一个用户态不可做,内核态可做的事件集合。 未实现。
这个没什么说的,不过是有现成的实现的([kTLS & eBPF](http://vger.kernel.org/lpc_net2018_talks/ktls_bpf.pdf)),但是本身如何集成到ebpf-cache-for-redis需要思考。 未实现。