如何设计一个运营商级的SIP Server?

How to design a carrier grade SIP Server?

有一些 SIP 服务器可以处理几千个订户,而另一些 SIP 服务器可以处理具有类似底层硬件的数百万个订户。实施能够处理如此大量流量的 SIP 服务器需要考虑哪些设计和开发因素?

首先,我假设您有兴趣构建自己的 SIP 信令应用程序,因此您的问题是针对 SIP 应用程序服务器和它们之上的应用程序 运行。我不会谈论像 Asterisk 这样的产品。 Java 包含 SIP servlet 容器的应用程序服务器没有那么多选择。基本上三巨头是 IBM 的 WebSphere 服务器、Oracle 的 Communications 服务器和 Mobicents。我最熟悉 WebSphere,您可以在 www.wasdev.net 免费下载它,但我确信所有这些产品在信号方面都可以很好地扩展。远远超过几千个端点,如果您愿意将服务器集群化,您可以相当轻松地支持每秒数千次调用。这就是像 AT&T 这样的一级供应商如何将他们的 Voip 服务扩展到大量端点。

如果您在问题中包含媒体处理,那么您很快就会遇到可扩展性问题。服务器端媒体处理(record/playback、多路混合、SFU 等)可能会占用大量处理器资源。在 SIP servlet 世界中,媒体服务器是通过媒体控件 API (JSR 309) 控制的,它从媒体平面描述了信令平面。因此,如果不进一步了解您的 SIP 服务器需要托管的应用程序类型,就很难回答您的问题。

有很多因素会影响依赖于 SIP servlet 容器的 SIP servlet 应用程序的可伸缩性。线程是关键。您希望确保您永远不会阻塞应用程序代码中的线程。一切都必须是异步的才能扩展。对于不习惯编写异步代码的开发人员来说,这可能需要一点时间来适应,但在进行任何实时信号开发之前弄清楚这一点至关重要。在 Java 服务器方面,您还希望调整 JVM 以获得最佳结果。这不仅仅是确保您有足够的堆 space 来容纳您的服务器必须支持的每秒调用次数。有许多 JVM 垃圾收集 (GC) 旋钮可以用来调整苗圃大小等。GC 配置适合您的服务器至关重要。大多数 JVM 还具有特定的 GC 算法,旨在更好地为实时应用程序工作。例如,与 IBM WebSphere 一起使用的 JVM 支持称为 metronome 的 GC 算法,该算法以 GC activity 换取低延迟。

这是一个很大的主题,所以如果您能提供更多有关您尝试使用 SIP 服务器完成的工作的详细信息,我可能会提供更多见解。

从纯标准 -rfc3261- 的角度来看,SIP 服务器处理 SIP 流量的目的是路由(寻找用户或其他服务器),除此之外别无其他。我假设我们在这里谈论的是 SIP 代理服务器。

在 SIP 服务器上使用 有状态无状态 模式处理传入请求。

您可以从 rfc3261 中获得两者的定义:

  Stateful Proxy: A logical entity that maintains the client and
     server transaction state machines defined by this specification
     during the processing of a request, also known as a transaction
     stateful proxy.  The behavior of a stateful proxy is further
     defined in Section 16.  A (transaction) stateful proxy is not
     the same as a call stateful proxy.

  Stateless Proxy: A logical entity that does not maintain the
     client or server transaction state machines defined in this
     specification when it processes requests.  A stateless proxy
     forwards every request it receives downstream and every
     response it receives upstream.

进入有状态代理服务器的传入 SIP 请求通常会存在很短的时间。这个持续时间通常会很短。例如,路由 BYE 将需要分配 2 个事务:一个传入和一个传出。它将存在于内存中,直到两者都达到 "terminated" 状态,如 rfc3261 的 图 6图 8 中所述。对于 TCP,Timer JTimer K 是 0 秒,因此,理论上的持续时间比接收应答的时间要长一些。对于 UDP,Timer J 为 32 秒,因此,分配的事务上下文必须在收到最后一个应答后至少存在 32 秒(以处理重传)。

为了优化内存,走得更快,可以使用无状态处理。然而,这意味着重新传输将需要新的计算来找出与第一次处理完全相同的结果。在高损耗或低流量下,与有状态模式相比,这可以增加 CPU 使用率。无状态模式还要求始终以完全相同的方式处理请求,通常用于拒绝 unwanted/broken 流量:这可能(?)有助于抵抗 DDOS 攻击,使用语法拒绝消息问题,或拒绝禁止的流量。

当然,下一个问题将是关于实现的:您需要使用好的 OS、好的线程、好的异步非阻塞 DNS 或套接字操作、关心内存使用、分配等...

您报告说存在处理几千订户和其他数百万订户的服务器:事实上,没有理由真正的代理 SIP 服务器不能处理数百万(当然,如果编码得当的话)。处理 "only" 几千个订阅者的服务器通常充当端点(如星号):它们根本不是 rfc3261 中描述的 SIP 服务器,即:SIP 代理服务器。

作为旁注,即使是真正的代理服务器通常也能够欺骗和插入媒体中继:处理 RTP 中继。虽然今天需要处理媒体建立(如果您没有 ICE),但这在带宽方面引入了严重的限制:95%(或其他什么?)的流量将变成 RTP 而不是仅 SIP,并且带宽将是服务器的限制。

当然,查看与 ser 相关的项目(ser、kamailio、opensips...)将证明上述所有内容:

  • 他们可以在有状态模式下处理事务
  • 他们可以在无状态模式下处理交易
  • 它们可以配置为仅执行路由
  • 如果以这种方式配置,他们可以处理大量订阅者
  • 如果您激活一些东西(rtp 中继、呼叫控制东西、状态...),服务器将不再只是一个代理,无论如何都会出现限制!