查看原文
其他

梁鑫:重构 - 在美股行情系统的实践

梁鑫 中生代技术 2021-09-05

梁鑫

读完需要

4分钟

速读仅需 2 分钟

作者:梁鑫(资深架构师,多年云原生,微服务架构经验,开源 SIA 系列产品 owner)

1


   

引子

今年开始,由于工作内容调整。开始负责美股港股产品的研发。第一个面对的问题,就是当前产品股票行情信息严重延迟。股票行情信息延迟,客户会看到的是错误的股价,这直接导致了产品的不可用,失去了客户的信任。

股票行情是一种证券市场用语,指股票交易所内各只股票的涨幅变化及交易流通情况。


2


   

旧版美股行情系统架构图

从现状的架构图中可以看出,美股行情产品有以下若干问题

2.1


   

问题一,消息服务器选择

相信很多朋友都对 rabbitmq 有所了解,很多公司都采用了 rabbitmq。它以传输速度快,可靠性高而被广为使用。在主流的开源消息服务器中,它是唯一可以传输速度达到微秒级的消息消息服务器。在实际传输中,即使使用集群,它也并不是真正的分布式队列服务器。所以在消息顺序上,它是保证的最好的。但 rabbitmq 也有自身的不足,最大的不足就是吞吐量太低。无法满足海量股票行情信息的传输需求。

2.2


   

问题二,缓存服务器 Redis 的使用

Redis 缓存服务的性能,相信可以满足大多数项目的需求。但如果降美股行情的数据量进行全量的写入操作,即使是 redis,也 cover 不住。虽然 Redis 号称能支持每秒 14 万的读操作,11 万的写操作。但这估计是理想的情况。在实际的生产环境中,我们的实际测试结果是达不到这个量级的。对于每秒超过十万的股票行情信息,每条数据都进行 redis 写操作,必然出现大量的写入失败,甚至频繁出现 redis 链接异常。

2.3


   

问题三,线程池的使用

在现存的架构中,多线程设计有着明显的问题。因为 rabbitmq 的吞吐量不足,因此技术上把数百条消息合并成一条进行传输处理,这样虽降低了消息吞吐量,不会导致消息大量堆积,但却对实时的股票行情数据造成了人为的延迟。即便进行了消息合并,但吞吐量还是过大,因此根据股票的名称把若干股票的信息分组用不同的队列进行传输。

每组股票都用一个线程池来处理。强行增大处理性能。当接到封装的信息后,为了保证能够处理大量消息,还需要采用多线程方式,因为股票行情需要有一定顺序行,无序的线程处理导致了大量时序错误信息, 最终发现展示结果很难使人满意。并且维护大量的线程池极度消耗资源,我们常规意义的线程配置,是计算有限 CPU 核数+1,IO 有限 CPU 核数*2。维护数百个线程池,其实是让线程切换的工作占据了大量的 CPU 时间,浪费了宝贵的 CPU 的资源。

2.4


   

问题四,系统无法进行水平扩展

如果判断系统是一个好的集群架构。往往需要满足三点要求。

  • 一是可以避免单点故障;

  • 二是可以水平扩展;

  • 三是能实现负载均衡。

现状股票行情架构是完全不能满足这三点需求。需要进行重构。


3


   

新版美股行情系统架构图


3.1


   

改进一,使用 kafka 替代 rabbitmq

美股行情信息吞吞量非常大,在开盘和收盘的高峰期甚至超过了每秒十万条交易信息。如此之大的吞吐量,很明显 rabbitmq 根本无法满足需求,只有采用吞吐更大的 kafka 才能满足需求。我们经常用下表来比对几种主流消息服务器的差异。


3.2


   

改进二,降低 redis 的写入次数

如何降低 redis 的写入次数,只能是把原先写入 redis 的操作变更成为写入内存。当股票行情信息通过 kafka 队列服务器将消息流转到股票计算节点时,计算节点把数据计算后写入内存,同时定期将内存数据同步到 redis 中,这样可以大大节省 redis 的写操作,让 redis 的性能能够 cover 我们现在的需求。同时我们将性能较差的 redisTemplate 换成直接使用 jedis,通过我们的测试,两者之间的性能差异接近三倍,并优化 redis 链接数,避免出现大量链接异常情况。

3.3


   

改进三,改进线程池的使用

现状系统的线程池创建太多,让宝贵的 CPU 资源浪费在了线程切换中。新的架构为了解决这个问题,获取每只股票的 hashcode,然后用固定线程数取余,每个余数给一个固定的线程池,每个线程池保活一个线程,这样就能保证每只股票在同一节点进入一个线程处理,最大限度保证了处理股票行情信息的顺序性。

3.4


   

改进四,支持水平扩展

通过对 kafka 同一个 topic 订阅,然后不同 worker 接收不同的信息,这样可以轻松让计算节点进行水平扩展。当信息再往下一个节点流转时,查询节点通过不同 groupid 订阅完整 topic,不需要再通过 redis,这样查询节点可以轻松进行水平扩展。支持了整体架构的水平扩展。

4


   

总结

美股行情的吞吐量,远超过我之前所负责过的项目。如此高的并发,且不能延迟,还要最大限度的保证处理信息的顺序性。对自己而言也是个不小的挑战,在这个项目中我学到了很多东西。

往期推荐

欧创新:深度解析DDD中台和微服务设计

领域驱动专家张逸文字脱口秀:简单工厂不简单

DDD专家张逸:《解构领域驱动设计》前言

Hacker News热文:请停止学习框架,学习领域驱动设计(DDD)(获500个点赞)

京东平台研发朱志国:领域驱动设计(DDD)理论启示

DDD专家张逸:构建领域驱动设计知识体系

领域驱动设计(DDD)在美团点评业务系统的实践

当DDD遇上微服务

DDD战略篇:架构设计的响应力

可视化与领域驱动设计

领域驱动设计(DDD)前夜:面向对象思想

领域驱动设计(DDD):领域和子域

DDD专家张逸:复杂与架构演进的关系

滕云:DDD实现之路

百度十亿级流量的搜索前端,是怎么做架构升级的?

Francisco: 构建前瞻性应用架构的优秀实践

这 3 种 DDD 分层架构的模式,你掌握了么?


   END     

#技术人必备#



点个在看,让更多人看见
: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存