这是一个问题,我已经研究了好几年,但现在我仍然没有得到一个很好的解决方案。
我的应用程序有两部分:
-
第一个在一个叫做"ROOT服务器"的服务器上运行。它将从香港证券交易所(香港证券期货交易所)接收实时股票数据,并将其广播到其他5个子服务器。它将在广播时为每个数据项附加时间戳。
-
第二个在"子"服务器上运行。它们将从ROOT服务器接收股票数据,解析每个数据,并获得重要信息。最后,他们将以新的文本格式发送给客户。客户可以有几百到几千个,他们可以注册某种股票,并获得他们的实时信息。
表现是最重要的。在过去的几年里,我尝试了各种各样的解决方案,我知道让它更快。这里的"更快"是指,第一个服务器将尽可能快地接收和发送数据到子服务器,子服务器将尽可能快地接收、解析和发送数据到客户端。
目前,当HKEx的数据速度为200K,并且有5个子服务器时,第一个应用程序平均每个数据项有10ms的延迟。第二个不容易测试,它取决于客户端数量。
我在用什么:
- OpenSUSE 10
- Sun Java 5.0
- 米娜2.0
服务器硬件:
- 4核CPU(我不知道类型)
- 4 g ram
我正在考虑如何提高性能。
- 我需要使用一个并发框架作为akka
- 尝试其他语言,例如Scala?c++吗?
- 使用实时java系统?
- 你的建议…
需要你的帮助!
更新:
应用程序已经记录了一些用于分析的重要信息,但是我没有发现任何瓶颈。明年港交所会提供更多的数据,我觉得我的申请不够快。
我的一个客户测试了我们的应用程序和另一家公司的应用程序,但我们的应用程序在速度上没有优势。我只是想找个方法让它快一点。
第一个应用程序如何运行
第一个应用程序将接收来自HKEx的股票数据,并将其广播到其他几个服务器。步骤如下:
- 连接香港交易所
- 登录
- 读取数据。数据为二进制格式,每项有一个头部,头部是2字节的整数,表示主体的长度,然后是主体,然后是下一项。
- 将它们放入内存中的hashmap中。Key为项的序列,value为字节数组。
- 将每个接收到的项目的顺序记录到磁盘中。使用log4j的缓冲区附加器。
- 一个守护线程试图从hashmap中读取数据,并每隔1分钟将它们插入到postgresql中。(仅用于备份数据)
- 当客户端连接到此服务器时,它接受它们并尝试从内存发送来自hashmap的所有数据。我在mina中使用线程池,接受者和发送者在不同的线程中。
我认为逻辑很简单。当有5个客户端时,我监测到的传输速度最多只有1.5M/s。我用java写了一个最简单的套接字程序,发现可以达到10M/s。
实际上,我花了一年多的时间在这个应用程序上尝试了各种解决方案,只是为了让它更快。这就是为什么我感到绝望。我需要尝试Java以外的其他语言吗?
约10ms延时
当应用程序收到来自HKEx的数据时,我会为其记录时间戳。当根服务器向子服务器广播数据时,它将在数据后面附加时间戳。
当子服务器获得数据时,它将向根服务器发送消息以获取当前时间戳,然后比较它们。因此,10ms延迟包含:- 根服务器得到数据-->子服务器得到数据
- 子服务器发送请求根服务器的时间戳->根服务器得到它
但是第二个非常小,我们可以忽略它。
要找到性能瓶颈,首先要找出大部分时间花在哪里。确定这一点的一种方法是使用分析器。
有开源的分析工具,如http://www.eclipse.org/tptp/,或商业的分析工具,如Yourkit Java Profiler。
一件简单的事情是将JVM升级到Java SE6或Java 7。JVM的一般性能在版本6中得到了很大的改进。详细信息请参见Java SE 6性能白皮书。
如果您检查了所有内容,但没有发现明显的性能优化,那么您可能需要更改架构以获得更好的性能。如果您至少可以确定您的应用程序在哪里花费时间,那么这显然是最有成效的—听起来有几个主要的组件:
- HK Ex服务器(不受您控制)
- Exchange和您的系统之间的网络
- "根"服务器
- 根服务器和子服务器之间的网络
- 子服务器
- 子服务器和客户端的网络
- 客户
要知道在哪里花费时间、金钱和精力,我至少希望看到对这些组件的分析,每个组件需要多长时间(最小、最大、平均时间),以及每种资源的规范是什么。
最容易改变的是硬件——更大的服务器,更多的内存等,或者更好的带宽。你能看到这些资源是否受到限制吗?
接下来要考虑的是改变通信协议以提高效率——客户端如何接收股票?你能减少数据的大小吗?只有5个客户,150万听起来很多…
接下来,你可能会考虑某种服务质量解决方案——为"高级"客户提供专用硬件,减少资源争用,提供更多服务器和更多带宽——这可能需要改变架构。
接下来,您可以考虑更改架构——现在,您的客户端从客户端服务器"拉"数据。相反,您可以"推出"数据—这样可以减少客户机端的轮询间隔。
在列表的最后,我会考虑不同的技术堆栈;Java是一种优秀的编程语言,但如果绝对性能是一个关键优先级,C/c++仍然更快。显然,这是一个巨大的变化,一个编写良好的Java应用程序将比一个编写糟糕的C/c++应用程序更快(而且更稳定)。
为了跟踪延迟的来源,我会将计时数据添加到您的端到端流程中。您可以使用外部日志或通过向消息中添加元数据来完成此操作。
你想要得到的是应用程序关键阶段的时间戳3-5就足够了。通常我会使用System.nanoTime(),因为我正在寻找微秒级的延迟,但在您的情况下,System.currentTimeMillis()可能就足够了,特别是如果您对许多样本进行平均(使用Ubuntu,您仍然可以平均获得0.1 ms的精度)
比较相同消息通过系统时的时间戳,并查找最高的平均延迟。一旦你发现了这一点,试着把这段时间分成更多的阶段来放大问题。
对于你的情况,我会分析任何平均延迟超过1毫秒的阶段。如果客户每分钟都在更新,那么这样做可能没有一个很好的技术理由,但你不想被认为是缓慢的,你的交易者处于劣势,即使在现实中这不会有什么不同。