Sofa memcached client

一、简介

Sofa 源于 Minisite 重构项目,也许您会问,已经有如此众多的 memcahced 客户端,为什么还要再来一个,我们经常会说,不要尝试去重复造轮子。是的,但如果我们有一种不同的思路来制造这个轮子,并且它有可能会做得更好,那为什么不试试看呢?基于此,才有了 sofa

二、 Sofa 的愿景

在不额外增加太多成本的情况下,更快速、高效的收发数据。

三、 sofa 的前辈们

在介绍 Sofa 的实现原理之前先简要了解一下,部分目前常用 Memcached 客户端的基本实现原理。

Spy

Spy 在处理命令时也利用了批量发送及接收的机制,但其数据的收发都是基于 Selector 处理线程,特点在于:

1. 读写都在一个线程中执行;

2. 写数据是先往 socket 中写,写不完则注册写监听;这种机制的缺点在于,在一次处理不完数据的情况下,写入数据的代码会被多执行一次(一次写循环,另外一次在写事件处理过程中);而且大部分情况下命令都是一个个被写入 socket 中,整体来看,这种模式会影响高吞吐量情况下的收发效率。

扫描二维码关注公众号,回复: 1296134 查看本文章

3. 读数据完全依赖 socket 的读事件来执行。

4. 命令本身是批量发送,但每个命令请求都会唤醒 Selector ,结果造成 Selector 被多次唤醒,执行过多的空循环。

另外: spy Selector 线程会根据 Client 创建而自动生成,如果创建多个 client ,那么就会创建多个 Selector 线程;

Xmemcached

Spy 不同, XM 完全基于 Socket IO 事件来驱动 IO 读写(在 Selector 处理线程中实现读写操作),任何命令读写都会直接注册读写相关的 IO 事件,然后等相应事件产生则往 IO 中写入或读取数据。

Spy 的主要区别在于:

1. spy 是先写数据,写不了才注册写事件,而 XM 则完全基于 IO 事件实现。

2. spy 会批量发送数据,而 XM 可以合并多个 Get 命令为一条 GETS 命令;

3. xm Selector 线程数是根据当前服务器的可用处理器个数来创建;

XMemcached 的核心 Selector 的代码写得相当精巧,整体性能表现稳定;

Danga

由于之前测试的版本是基于阻塞式 IO 实现,其在吞吐量及相应速度方面要相差一个数量级,所以一直没有太多的关注,在此不做太多评价。但由于其是 Memcached 最早的 java 客户端,使用比较广泛,稳定性也不错。

 

 

Cat Alibaba 自己的 Memcached Client 实现):

Cat 的实现类似 spy 但又有所不同,类似点在于:写数据在 Selector 线程中执行,如果数据没有写完,才注册写事件。但其 Selector 线程数量计算方式有点特别,如果处理器小于 8 核,则只创建一个 Selector 线程,否则创建 4 Selector 线程;另外, Cat 的实现基于连接池的实现机制,对于同一个 Memcached Server Cat 会根据并发请求数,创建对等的 TCP 连接( TCP 模式下)。在我的测试机上,如果 50 个并发, cat 会同时建立 50 TCP 连接。最后一个不同点是 Cat 的命令收发都是独立的,即每个命令都会单独占用一个 socket 来发送和接受,直到处理完当前命令, socket 才空出来给下一个命令使用 没有批量发送和命令合并的功能。但通过多个连接可以实现类似批量发送的功能,整体卡端的 IO 复用率还是比较高的。

四、 sofa 的特点:

       1. 收发并行的工作模式,写入时直接往通道中写入数据,读取完全依赖IO 通道中的读事件。

2. 批量处理命令的工作模式: a 、命令的批量发送, b 、多个 get 命令自动合并成一个 gets 命令

3. 基于 nio 的收发模式,可以同时管理多个连接,并且在请求线程急剧增加的情况下,整个收发效率变化平稳。

4. 支持所有 memcached 的标准命令,并且支持二进制和字符串两种命令格式。

5. 支持 direct buffer 模式读取数据(目前只支持 Text 命令模式)。

五、 Sofa 的实现原理:

Sofa 的实现和上述的几个客户端有很大的区别,首先是 sofa 数据收发模式,读写是并行执行的,如下图:


 

同样在读取数据时也采用类似的机制来实现,由于网卡本身都是全双工的方式工作,因此在多核的系统中,读写的并行可以极大的增加单个连接的数据吞吐量,同时在写 入数据时, sofa 的实现方式是首先尝试直接写,只有底层 socket 中无法写入数据时,才向 selector 注册相关的监听事件,在 Memcached Server 这种请求响应时间几乎恒定的服务器支撑下,可以极大的减少同 selector 的交互次数,在压力测试机上测试统计发现,约 90% 的数据都可以不通过 selector 而直接从 socket 中写入。

其次、 sofa 也采用同 spy 类似的方式,为每个 socket 都维护了一个命令队列,发送时系统从命令队列中获取一批命令数据,并将其一次性发送给 memcached 服务器端,同时对于多个 Get 命令, sofa 会自动合并成一条 Gets 命令,这样可以减少数据发送时往网卡缓存写入数据的次数,进而减少底层网络数据的发送次数

最后、 sofa 对命令数据的压缩和解压操作都不放在核心读写线程来实现,为了保证读写线程的高效率,这些操作全部转移到请求线程来处理。

 

六、性能测试

附件是 spy xmemcached sofa cat 之间的性能测试对比 , 性能测试对比图:见附件

性能对比测试粗略分析

测试 Client 1 5 10 20 50 100 150 200 个并发线程模式下,各个 client 的整体吞吐量 TPS (第一列图)及在当前压力下随机读写两次数据的响应速度测试(第二列图)。

1. 吞吐量( TPS ):

从图中可以看到在大部分情况下, sofa 能够获取更高的吞吐量( 20% 100% 左右的性能提升),有些场景 TPS 会有近 1 倍的提升。

XM 整体的稳定性较好,随着线程数和数据量大小的增加,各方面性能表现都比较稳定;

2. 压力测试下,随机访问速度测试:

测试在相应的并发压力下,随机访问的性能对比, sofa 总体而言和 xm 系统差不多,甚至某些情况下还会稍微快些。

  1. 连接数:

xm spy sofa :在所有场景下都只是用了一个 TCP 连接;

cat :连接数随并发数增加而增加,每个并发会对应一个 TCP 连接;

七、 Sofa 的未来

说实话,我也不是太清楚,如果你喜欢或者有兴趣,或许可以和我一起来完善它,我相信Sofa 还存在很大的优化空间,占有更少的系统资源,获取更快的收发速度;

如果想在自己的产品中尝试使用它,对 sofa 而言绝对是个好消息,不管如何,它都需要大家的支持才有可能能走得更远 更好。

未来计划:

加入更多的异常处理机制,诸如连接自动重建,多备份数据读写等等;

加入 UDP 的支持

优化核心模块,让其占用更少的资源消耗,尤其是内存分配与释放相关的部分。

猜你喜欢

转载自san-yun.iteye.com/blog/1747289