OKEX闪电系统2.0升级 电子交易系统( 二 )


此外,对于现代CPU来说,从内存中访问数据仍然不够快 。从实际测试结果来看,从L2缓存获取数据的时间仅为从内存获取数据的1/7 。为了进一步降低系统延迟,如何利用好CPU缓存成为关键 。CPU访问内存时,最小单位是缓存行,通常是64字节 。当CPU加载内存时,它会将相邻的64个字节的数据放入缓存 。基于以上现实,OKEx通过控制数据在内存中的分布,从两个方面对Lightning系统进行了改进:
控制内存分配,把需要连续处理的数据放在一起 。当所有数据放在一起,读取多条数据时,只需要第一次从内存加载到缓存,后续的读取就可以命中缓存,从而提高性能 。
控制内存分配,将可能高速变化的数据(如计数器)放入不同的缓存行 。当多个CPU同时修改同一缓存行中的不同字节时,就会出现伪共享的问题 。例如,CPU1修改自己的数据 。当CPU2再次读取自己的数据时,CPU2必须重新加载整个缓存行,因为缓存行中的一些数据已经被更新 。两个CPU需要互相等待 。为了避免这种现象,OKEx通过填充使这些数据位于不同的缓存行中 。
2.通信模式-“发布/订阅”模式和二进制消息格式
目前,系统中主要有两种通信模式:
发布/订阅模式和请求/响应模式的区别在于,发布/订阅模式中的通信是通过消息队列完成的 。当一个服务需要请求其他服务时,它将请求的相关信息封装成消息发送到消息队列,其他服务订阅消息队列获取信息并处理请求 。
显然,在“请求/响应”模式下,客户端和服务器是强耦合的,两者都需要同时可用,客户端只能在服务器处理请求之前等待,降低了客户端的处理速度;在“发布/订阅”模式下,服务的调用者将消息发送到消息队列后,完成当前请求的处理,具有解耦特性;另一方面,当订阅者的服务中断时,消息会持久保存在消息队列中,当服务恢复时,会继续处理,发布者不需要重新发送消息,提高了系统通信的可靠性 。因此,在OKEx的闪电2.0交易系统中,几乎所有场景都采用“发布/订阅”模式,不仅提高了可用性,也提高了系统的吞吐量 。
通信方式确定后,下一个重要问题是消息格式的选择 。通信的本质是交换消息,消息通常包括数据 。消息的格式会影响通信效率、通信的演进以及系统选择的编程语言,所以一个重要的设计就是确定数据格式 。
基本上,有两种消息格式:文本和二进制 。
基于文本的消息格式的性能缺陷是显而易见的:除了消息容易出错外,当消息较大时,解析文本会带来巨大的开销,这对于交易系统这样对效率和性能敏感的系统来说是不可接受的;另一方面,基于二进制的消息是以机器容易解析的方式定义的,因此性能通常比基于文本的消息高得多 。因此,OKEx的闪电2.0交易系统选择了基于二进制的通信报文格式 。
3.水平扩展下的负载再平衡
为了提高系统的处理能力,需要扩展系统的处理能力 。一般来说,扩张可以分为横向扩张和纵向扩张两种方式 。纵向扩展等于升级服务器,横向扩展等于增加服务器 。服务器的单一硬件性能受限于人的生产力 。当机器的硬件配置达到一定程度,无法进一步提升(单一硬件性能极限),横向扩展成为唯一选择 。但是横向扩展模式会带来负载均衡的问题,即整个系统的负载应该如何分配到各个计算机信息资源网络上?
首先要考虑的是数据的竞争 。虽然增加机器可以提高系统的并行处理能力,但是如果并行处理不合理,可能会导致多台机器频繁竞争相同的数据,系统的处理能力无法得到有效提高 。
对于交易系统来说,数据主要包括订单、用户的资金和持仓 。然后为了减少这种竞争,一个分配策略很明显,根据用户进行负载碎片化 。不同用户的订单、资金、持仓独立处理,避免了竞争,甚至我们可以重新优化,对同一用户增加批处理,进一步提高系统的处理能力 。另一方面,通过交易对(这里主要指合约交易)的保证金隔离,我们又多了一个负荷碎片化的维度:交易对 。对于同一个用户,不同的事务对是完全独立的 。这样,我们根据两个维度来划分负载 。当系统需要添加更多机器时,我们根据切片策略重新平衡负载,实现了系统扩展的灵活性 。
4.模块拆分
提高系统可维护性和可扩展性的主要途径是对系统进行拆分 。在此次OKEx交易系统升级中,我们进一步将原有的交易服务拆分为撮合、柜台、风控模块 。每个模块维护自己的内部数据和状态 。具体来说,撮合负责维护订单簿,专柜负责维护用户的持仓和余额,风控负责风险管理 。


推荐阅读