【问题标题】:High-Availability TCP server application高可用性 TCP 服务器应用程序
【发布时间】:2020-09-06 12:58:00
【问题描述】:

在我的项目中,我有一个运行 C# 应用程序的云托管虚拟机,它需要:

  1. 接受来自多个外部客户端的 TCP 连接(大约 500 个)
  2. 从连接的客户端异步接收数据(频率不高,大约每分钟 1 条消息)
  3. 对收到的数据做一些处理
  4. 将收到的数据转发给其他参与者
  5. 回复连接的客户端并可能进行一些异步发送(基于内部时间检查)

在我看来,这个设计很简单。我提供了一个接受传入 TCP 连接的侦听器,当建立新连接时会产生一个新线程;该线程在循环中运行(执行从 2 到 5 的活动点)并检查关联的套接字活动(如果套接字已死,则线程退出循环并最终终止;稍后将从套接字所属的外部客户端尝试新连接到)。

所以现在的问题是,对于有限数量的外部客户端(我会说 200/300),一切运行顺利,但随着数量的增长(或者当客户端以更高的频率发送数据时),通信变得非常缓慢和受阻.

我正在考虑一些更好的设计,例如:

  • 使用任务而不是线程
  • 使用线程池
  • 将 1Thread1Socket 替换为 1Thread10Socket 之类的东西

甚至一些扩展策略:

  • 在同一个应用程序中打开两个不同的 TCP 侦听器(不同的端口)(重新配置客户端,使其中一半针对每个侦听器)
  • 在同一虚拟机上提供两个具有两个不同 TCP 侦听器(不同端口)的相同应用程序
  • 设置两个不同的虚拟机,每个虚拟机上运行相同的应用程序(重新配置客户端,使其中一半针对每个虚拟机地址)

最后的问题是:当前的设计是糟糕还是幼稚?你觉得我处理沟通的方式有什么重大的关键吗?你有没有更强大和有效的选择(在上面提到的那些,或者任何其他的)?

谢谢

【问题讨论】:

  • 已知每个连接的线程不能很好地扩展。
  • 是的,完全反模式。并且完全忽略那里存在的批量 API - 回到文档。而且您的一些扩展策略(尤其是第一个)听起来完全像是不阅读文档(即选择仅选择有数据等待的套接字)。目前的设计很幼稚。还有这个 ftopic 的问题。
  • @TomTom 你能不能给我提供几个有用的链接来更好的模式?谢谢
  • 当然。 docs.microsoft.com/en-us/dotnet - 我把它当作一个练习来了解框架以在 Socket 类上找到 Select 方法。

标签: c# multithreading tcp communication scalability


【解决方案1】:

听众的数量不太可能成为限制因素。在 Stack Overflow,我们每个实例处理大约 60k 个套接字,我们需要多个侦听器的唯一原因是我们可以将流量分配到多个端口以避免负载平衡器的临时端口耗尽。同样,我应该指出,每个实例 60k 的套接字服务器运行在基本上零 CPU,因此:考虑多个 exe、VM 等还为时过早。那不是 问题。问题在于代码,而将糟糕的套接字基础设施分布在多个进程上只会隐藏问题。

编写高性能套接字服务器困难,但好消息是:您可以避免大部分情况。 Kestrel(ASP.NET Core http 服务器)可以充当完美的 TCP 服务器,为您处理大部分可怕的异步、套接字、缓冲区管理等,所以您只需要担心的是实际的数据处理。 “管道” API 甚至会为您处理后台缓冲区,因此您无需担心过度读取。

my 3-and-a-bit part blog series starting here 中有一个详细的演练 - 它只是方式 太多的信息尝试在这里发布。但它链接到一个演示服务器——一个虚拟的 服务器hosted via Kestrel。它也可以在没有 Kestrel 的情况下托管,使用 Pipelines.Sockets.Unofficial,但是...坦率地说,我会使用 Kestrel。那里显示的服务器与我们的 60k-per-instance web-socket 层大体相似(在广泛的初始化方面 - 而不是它所做的实际事情)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-07
    • 2011-01-29
    • 2011-12-20
    • 1970-01-01
    • 2017-05-08
    • 2012-05-30
    • 2011-03-21
    • 2016-10-02
    相关资源
    最近更新 更多