实例的连接池和扩展

时间:2017-07-27 14:12:28

标签: spring oracle spring-boot database-connection cloudfoundry

注意:这是一个与设计相关的问题,我无法找到令人满意的答案。因此在这里问。

我有一个部署在云端的云启动应用程序(Cloud Foundry)。该应用程序连接到Oracle数据库以检索数据。该应用程序使用连接池(HikariCp)来维护与数据库的连接。可以说连接数设置为5.现在,应用程序可以根据负载自动扩展。所有实例都将共享同一个数据库。在任何时候都可以运行50个相同应用程序的实例,这意味着数据库连接总数将为250(即5 * 50)。

现在假设数据库只能处理100个并发连接。在当前场景中,20个实例将耗尽100个可用连接。如果接下来的30个实例尝试连接到db会发生什么?如果这是设计问题,如何避免这种情况?

请注意,为简单起见,问题中提供的数字是假设的。实际数字要高得多。

1 个答案:

答案 0 :(得分:2)

让我们说:

  • 可用数据库连接数= X
  • 您的申请的并发实例数量= Y
  • 应用程序的每个实例中数据库连接池的最大大小= X / Y

这有点过于简单,因为您可能希望能够从其他客户端(例如支持工具)连接到您的数据库,因此更安全的公式可能是(X * 0.95) / Y

现在,您已确保您的应用程序层不会遇到“不存在数据库连接”问题。但是,如果(X * 0.95) / Y是25,并且您有超过25个并发请求通过您的应用程序同时需要数据库连接,那么其中一些请求在尝试获取数据库连接时会遇到延迟,如果这些延迟超过配置的超时,则会导致请求失败。

如果您可以限制应用程序中的吞吐量,那么您永远不会有超过(X * 0.95) / Y并发“获取数据库连接”的请求,那么问题就会消失。但是,当然,这通常不太现实(事实上,因为少了很少...告诉你的客户停止与你交谈通常是一个奇怪的信号发送)​​。这将我们带到了问题的关键:

  

现在,应用程序可以根据负载自动扩展。

向上缩放不是免费的。如果您在处理N并发请求时需要相同的响应能力,就像处理100000N并发请求时那样,那么必须给出一些东西;你必须扩大这些请求所需的资源。因此,如果他们使用数据库连接,那么数据库支持的并发连接数将不得不增长。如果服务器端资源不能按比例增加到客户端使用,那么您需要某种形式的背压,或者您需要仔细管理服务器端资源。管理服务器端资源的一种常用方法是......

  • 使您的服务无阻塞,即将每个客户端请求委托给线程池,并通过服务中的回调响应客户端(Spring通过DeferredResult或其Async框架或其RX集成来促进这一点)
  • 根据服务实例的客户端请求线程池的总大小配置服务器端资源(例如数据库允许的最大可用连接数)以匹配服务的最大吞吐量

客户端请求线程池限制每个服务实例中当前活动请求的数量限制客户端可以提交的请求数。此方法允许服务向上扩展(由跨所有服务实例的客户端请求线程池的大小表示的限制),并且这样做允许服务所有者安全地保护资源(例如他们的数据库)不被过载。并且由于所有客户端请求都被接受(并委托给客户端请求线程池),因此客户端请求永远不会被拒绝,因此从他们的角度来看,就好像扩展是无缝的一样。

这种设计通过服务实例集群上的负载均衡器进一步增强,这些服务实例在它们之间分配流量(循环甚至通过某种机制,每个节点通过某种机制报告其“繁忙程度”,其中反馈被用于指导负载均衡器的行为例如将更多的流量引导到NodeA,因为它未被充分利用,因为它被过度利用而导致NodeB流量减少。

以上对非阻塞服务的描述只是划伤表面;他们有更多的东西(以及大量的文档,博客帖子,互联网上有用的东西)但是考虑到你的问题陈述(面对来自客户端的负载增加而担心服务器端资源)这听起来像是一个好的适合。