需要超快速的邮件系统吗?

设计和构建快速系统的最终指南。

如今,有许多技术可以连接数字系统,服务和设备。 HTTP和Messaging系统,例如NATSgRPCKafka可能会浮现在脑海。 这些系统的速度和性能对于效率和规模至关重要。 速度和效率还会导致负载下系统的可预测和确定性行为,我认为这是更可取的。 良好的表现是良好的,可预测的性能是伟大的!

那么,您将如何为性能和可伸缩性设计和构建系统?

消息系统旨在跨不同的网络传输(例如TCP / IP,UDP,WebSocket,蓝牙,LoRa)传递消息。 他们可以具有代理或服务器组件,或者客户端可以直接彼此通信。 我的大部分历史都与基于服务器的系统有关,在该系统中,客户端与服务器通信,然后服务器将消息分发给一个或多个收件人。 尽管有些人可能希望系统直接从一个客户端与另一个客户端进行通信,但是我认为服务器/代理方法更有效,因为服务器易于运行和操作,群集良好,因此它们可以在任何地方运行,并且具有弹性和良好的性能。 我将参考NATS项目介绍这些主题,该项目是我创建的,用作我在VMWare创建的项目CloudFoundry的控制平面。

每个IO调用的消息。

这是正确的第一个也是最重要的。 在用户空间和内核空间之间移动非常昂贵。 如果您为发送或接收的每条消息调用内核,则将降低性能。 我始终会测量每个IO呼叫获得的入站和出站消息数量。 对于Ingress,这要容易一些,因为您可以预分配缓冲区并执行我所说的盲读。 一次调用即可为您阅读尽可能多的内核。 通常,这不会影响入站邮件的延迟。 请注意,要使这些缓冲区的大小动态增长和缩小以匹配流量,否则,当您扩展到大量连接时,它将浪费内存。

对于出口,还是将消息发送出去,它成为吞吐量与延迟之间的平衡游戏。 将消息从消息服务器中移出非常重要。 我通常通过让一个单独的线程或协程实际执行对内核的IO调用来解决此问题。 这允许用户空间将多个消息合并在一起,再次尝试使每个IO调用的消息最大化。 我不希望这种内部缓冲不被取消,因此用户空间可以达到一定的限度,以有目的地拥有IO调用的所有权,从而实际上减慢了潜在的上行速度,并避免了由于内部缓冲而导致的大量内存消耗。 如果某人不能跟上,快速失败并切断它们,否则您将冒一个坏苹果为他人服务的风险。 还应测量到IO线程或协程的信令和交换成本,以在吞吐量和延迟之间实现良好的平衡。 您还应该测量合并缓冲区与使用Scatter和Gather语义(如果支持,则为writev)相比如何影响性能。

为了消除使用dpdk和其他仅用户空间的网络从用户到内核空间的跳跃,还做了很多有趣的工作。 我更感兴趣的是能够通过eBPF之类的机制将处理过程推入内核,甚至到NIC卡之类的网络元素上。

邮件路由

在支持多种消息模式(例如pub / sub或1:N,请求/答复和负载平衡的动态队列)的消息传递系统中,从性能角度来看,消息的路由变得非常重要。 在主题和/或主题功能丰富且涉及多个级别和通配符支持的系统中,将入站主题映射到一组收件人可能变得不那么容易。 同样,如果主题空间的变化率很高,那么如果没有正确的体系结构,这也会对分发性能产生不利影响。 在我的职业生涯中,我可能花费了大量时间来解决这一问题,我相信我仍然没有完全正确的方法。 在NATS中,主题由以“。”分隔的标记组成。 或点。 对于发布者,所有主题都必须是文字,但是,订阅可以具有通配符,以将不同的发布主题组合到一个订阅者回调/处理流中。 在NATS中,我们有一个标记或部分通配符“ *”,以及一个终端全通配符“>”。 例如,我可以订阅“ foo.bar。*”,然后将其发送给“ foo.bar.baz ”或“ foo.bar.22消息,而不是“ foo.bar”消息 。 如果我在NATS上订阅了“ foo。>” ,那么任何发布到“ foo.1”,“ foo.bar.baz”等的内容都可以使用。 有关通配符可能使用的功能的更多信息,请参见有关基于主题的寻址的 NATS.io文档。

NATS中主题分发者的后备存储是修改后的Patricia树或Radix树 。 唐纳德·R·莫里森(Donald R. Morrison)于1968年首次描述维基百科,他称之为“帕特里夏树”。 [4]该名称来自首字母缩写词 PATRICIA ,它代表“ 检索字母数字编码信息的实用算法 ”。 当主题层次结构具有许多叶节点时,此结构在节省空间方面效果很好。 TIBCO在Rendezvous(和EMS)和财务领域(认为股票报价分配)方面的早期工作表明,一般的树形结构可能非常适合。 例如,在主题空间为“ foo.bar.baz。[1–1,000,000]”的情况下,只有1M叶子节点是不同的,并且将共享foobar的公共节点。 在可预测的数据访问和缓存友好性更为重要的现代计算机体系结构中,带有链接的树形结构并不流行,但仍然非常有效。 我在NATS中使用的结构将链接和哈希用于级别,因此是一种组合。 您给它提供一个主题,它返回普通订户和队列订户的结果列表。 对于NATS,它们的处理方式不同,因此结果集将它们分开。 尽管这是有效的,但是如果这是我们使用的唯一数据结构,则NATS的性能将不如该部门那么好。 许多线程/协程可能正在访问此结构。 使用读/写锁以及某些区域的原子会有所帮助,而且我确实在面向Patricia树的数据结构中内置了一种L2缓存。 泰勒·特雷尔( Tyler Treat)的一位前同事认为,我们应该重做结构以使其无锁,并使用原子和CAS。 从表面上看,这总是很吸引人,但很少能产生您所期望的结果。 相反,我试图实现的目标类似于处理器和缓存的工作方式,并且在最佳情况下,每个入口处理器都具有无锁且无竞争的数据结构,该结构可处理大多数消息分发。 当然,对于L2共享缓存和用于入口处理的L1独立缓存,缓存无效在这里都很重要。 对于L2,我们尝试变得更加智能,并使用较小的缓存行进行失效。 这些是在传统的锁定方案下完成的。 对于独立的L1,我对主题分发者的世代ID进行原子检查。 如果已更改,则不要试图变得太聪明,我只需删除整个L1缓存,然后从共享的L2或支持树本身重新填充它即可。 对于单个入站流,现代硬件上的NATS服务器每秒可以处理大约2000万条消息,这还不错。 那只是一条流! 但是同样,如果分配器的更改率增加并导致更多的缓存失效,这将开始受到影响。 如果我有空的话,我可以回到这张桌子上的绘图表,但是现在对于适度改变主题空间的吞吐量我还是很满意的。

协议解析器

这是我的#3,但仍然很重要。 NATS是基于文本的协议,许多人认为只有二进制协议才能表现良好。 我已经设计并实现了两者。 我认为基于文本的协议不会受到性能的影响,但是协议解析器需要高效。 最初的NATS服务器很快就被写入了,以便CloudFoundry用作系统的控制平面。 我用Ruby编写了原始版本,尽管今天的版本是用Go编写的。 虽然我仍然喜欢C,但是我怀疑我会在以后的工作中大量使用它。 从一开始,Go就一直是我选择网络基础结构的语言。

尽管如今的NATS相当复杂,并且我没有计划用另一种语言来重写服务器,就像我将其从Ruby移到Go时一样,但Rust引起了我的注意,并且我正在像其他许多人一样看它。 Bryan Cantrill的帖子读得很好。 我最兴奋的是WebAssembly,但这是另一篇文章。

回到协议解析器,Ruby中的原始解析器是使用正则表达式编写的。 这不是因为我很懒,而是因为与使用Ruby本身遍历输入流相比,Ruby中的RegEx速度非常快。 当然,当我们使用Go这样的编译语言时,这种性能优势不再明显。 NATS服务器的协议解析器是一个接近零分配的手动解析器,可以处理拆分缓冲区,大消息,文本到整数的转换,并且性能非常好。 在Go的早期,文本转换实用程序并不是超级高性能,因此您仍然会看到很多我们自己编写的例程,这些例程将文本移至数字并返回等,以了解早期的性能挑战。刚开始使用Go时,请随时观看我在丹佛举行的首届GopherCon上的演讲。 它详细介绍了本文中介绍的许多关键性能领域。 多年来,Golang在围绕基本数据结构(如地图和垃圾回收)的性能方面做出了令人惊奇的事情。 它背后拥有一支不可思议的团队。 对我们来说,这是一个绝佳的选择。

可扩展性

最后但并非最不重要的是可伸缩性或大规模性能。 重要的是要了解您是否遇到性能问题或可伸缩性问题。 如果您的系统对于单个用户(或在这种情况下,单个客户端连接)运行缓慢,则会出现性能问题。 如果您的系统对于单个客户端连接速度很快,但是对于许多连接速度却很慢,则系统存在可伸缩性问题。 在讨论消息路由时,我们已经看到了这一提示,并且在主题分发器中有多个缓存层,以避免大规模竞争。 具有许多高消息速率连接的现代硬件上的NATS服务器可以处理近100M msgs / sec。 如果您考虑没有交叉的单独消息流,那么我们应该尽可能接近线性扩展,直到达到CPU /核数为止。 实际上,这很困难,因为我们开始对缓存和锁定结构进行强制同步。 在上面的示例中,共享单个主题空间和数据结构来路由消息将严重损害我们的可伸缩性,甚至对订阅的更新速度也很小。 如果硬件具有以下资源,我将集中精力确保它们可以并行和并行运行。

  1. 连接入口处理。 这是协议解析器。 在每个连接的处理方面,它们应该是独立的。
  2. 邮件路由。 已经讨论过这一点,但是已经在此体系结构中付出了很多努力以使其执行和扩展。
  3. 邮件出口。 即使多个入口源合并到单个出口流中,它也应该能够大规模运行。

我在2011年做过关于可扩展和可用的成功模式的演讲。 如果您有时间并且对本帖子有很多补充,那么值得进行演练。

https://www.slideshare.net/derekcollison/scalable-and-available-patterns-for-success-7196090

结论

到目前为止,如果您做到了,那就恭喜! 我从事此工作已有近30年的时间,但是我仍然很高兴能够设计和构建简单快速的系统! 我希望上面的一些讨论点可以帮助您设计和构建自己的快速有效的基于网络的服务。

如果您喜欢这个,请单击下面的so,以便其他人可以在Medium上看到此内容。

推特: @derekcollison

From: https://hackernoon.com/want-a-super-fast-messaging-system-c19c9f8cf560

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值