如何增强 Spring Boot REST API 以处理数以万计或更多的传入请求?
How to enhance a Spring Boot REST API to deal with tens of thousands or more incoming requests?
所以我一直在准备和进行采访。我在 2 次采访中被问到这个问题,但我无法给出令人满意的答案,或者可能不是他们想听到的答案。
问题是,让我们撇开负载平衡、多实例、数据库复制等各种操作技术,您可以在您的应用程序中进行哪些更改,即 REST API 以使其能够处理大量请求?
到目前为止我的想法是,我们可以使任何数据库或其他 API 调用异步,让它们 运行 在后台的单独线程中,以便处理可以移动关于其他请求。
我的一位同事说使用缓存来减少数据库调用。
也许可以增加线程池的大小,但线程很昂贵,而且您只能创建这么多线程。此外,如果池中的所有线程都处于忙碌状态,则其他请求将被阻塞,直到有一个线程可用为止。所以,这似乎真的不能归类为解决这个问题的方法。
总的来说,我们得出的结论是,在那种情况下,除了确保 API 应该只执行轻量级操作(如果有任何意义的话)之外,我们真的无能为力。
我用谷歌搜索了同样的东西,但除了操作和线程池之外,没有真正找到任何东西。
我想知道社区是否可以就此提供意见。你是如何处理这种情况的?
要在 spring 中获得最佳性能,您可以做很多事情,这里有一些。
被动
使用反应式非阻塞线程模型。当您的应用程序充当传递时,这是非常有益的,基本上如果您收到休息请求,那么您的应用程序需要向 3rd 方应用程序发出休息请求,利用反应模型将允许重新使用这些线程在外部服务处理请求时。
无国籍
让您的服务无状态
安全
使用 JWT 而不是每次都需要执行数据库查找的 Oauth 令牌。
缓存
尽可能缓存所有内容。
尽可能使用本地缓存而不是分布式缓存
DB
使用像 Hikari 这样的快速连接池
确保您的连接池具有最佳配置。
优化查询。更快的响应时间意味着更多线程可用于处理。
线程管理
正确配置用于执行程序的线程池会对应用程序性能产生很大影响。但是,此配置必须基于您系统的可用资源和应用程序的需要。
微糖架构
如果您正确使用微服务架构,每个服务将只接收与其域相关的请求,这可以减少整个应用程序的需求。
服务器选择
使用 Undertow 或 Netty 嵌入式服务器
优化 JVM
优化应用程序或容器的 JVM 内存使用。
首先想到的问题是什么类型的请求?为简化起见,假设有两个配置文件,读取密集型或写入密集型,并详细说明两者。
如果应用是读取密集型应用:
将大部分精力投入到缓存中。您可以在多个级别缓存,在 REST 级别完全缓存响应。根据您的目标一致性级别,还可以在服务和存储库级别进行缓存。
如果所有请求都针对相同的 keys
,并且您的对象相当小以适合应用程序的内存,您可以使用本地解决方案,否则您将需要缓存服务提供商来卸载缓存,像 Redis、Memcached 之类的东西。我不想特别鼓励任何人,因为他们会不时改变社区的偏好。
这种方法背后的原因是从 L2(甚至主内存)读取比到达数据库(实际从磁盘读取时)快几个数量级。查看更多次数here
如果应用是写入密集型应用:
或者上面的方法是不够的,考虑到即使你正在缓存你也必须在某个时候填充这个缓存,然后是时候移动到 no-sql/distributed 数据库,如 mongodb、cassandra、elasticsearch 等,取决于您的 CAP requirements. Some examples here。
这些数据库专为高吞吐量而设计。您还可以在 AWS 上查看它们的等效项。可能必须对您的数据进行一些非规范化以避免昂贵的(或明显不受支持的)连接。
我不确定更改数据库是否在这些问题的范围内,但缓存和数据库通常是可以实现最大性能改进的地方。
祝下次好运!
所以我一直在准备和进行采访。我在 2 次采访中被问到这个问题,但我无法给出令人满意的答案,或者可能不是他们想听到的答案。
问题是,让我们撇开负载平衡、多实例、数据库复制等各种操作技术,您可以在您的应用程序中进行哪些更改,即 REST API 以使其能够处理大量请求?
到目前为止我的想法是,我们可以使任何数据库或其他 API 调用异步,让它们 运行 在后台的单独线程中,以便处理可以移动关于其他请求。 我的一位同事说使用缓存来减少数据库调用。
也许可以增加线程池的大小,但线程很昂贵,而且您只能创建这么多线程。此外,如果池中的所有线程都处于忙碌状态,则其他请求将被阻塞,直到有一个线程可用为止。所以,这似乎真的不能归类为解决这个问题的方法。
总的来说,我们得出的结论是,在那种情况下,除了确保 API 应该只执行轻量级操作(如果有任何意义的话)之外,我们真的无能为力。
我用谷歌搜索了同样的东西,但除了操作和线程池之外,没有真正找到任何东西。
我想知道社区是否可以就此提供意见。你是如何处理这种情况的?
要在 spring 中获得最佳性能,您可以做很多事情,这里有一些。
被动 使用反应式非阻塞线程模型。当您的应用程序充当传递时,这是非常有益的,基本上如果您收到休息请求,那么您的应用程序需要向 3rd 方应用程序发出休息请求,利用反应模型将允许重新使用这些线程在外部服务处理请求时。
无国籍 让您的服务无状态
安全 使用 JWT 而不是每次都需要执行数据库查找的 Oauth 令牌。
缓存 尽可能缓存所有内容。 尽可能使用本地缓存而不是分布式缓存
DB 使用像 Hikari 这样的快速连接池 确保您的连接池具有最佳配置。 优化查询。更快的响应时间意味着更多线程可用于处理。
线程管理 正确配置用于执行程序的线程池会对应用程序性能产生很大影响。但是,此配置必须基于您系统的可用资源和应用程序的需要。
微糖架构 如果您正确使用微服务架构,每个服务将只接收与其域相关的请求,这可以减少整个应用程序的需求。
服务器选择 使用 Undertow 或 Netty 嵌入式服务器
优化 JVM 优化应用程序或容器的 JVM 内存使用。
首先想到的问题是什么类型的请求?为简化起见,假设有两个配置文件,读取密集型或写入密集型,并详细说明两者。
如果应用是读取密集型应用:
将大部分精力投入到缓存中。您可以在多个级别缓存,在 REST 级别完全缓存响应。根据您的目标一致性级别,还可以在服务和存储库级别进行缓存。
如果所有请求都针对相同的 keys
,并且您的对象相当小以适合应用程序的内存,您可以使用本地解决方案,否则您将需要缓存服务提供商来卸载缓存,像 Redis、Memcached 之类的东西。我不想特别鼓励任何人,因为他们会不时改变社区的偏好。
这种方法背后的原因是从 L2(甚至主内存)读取比到达数据库(实际从磁盘读取时)快几个数量级。查看更多次数here
如果应用是写入密集型应用: 或者上面的方法是不够的,考虑到即使你正在缓存你也必须在某个时候填充这个缓存,然后是时候移动到 no-sql/distributed 数据库,如 mongodb、cassandra、elasticsearch 等,取决于您的 CAP requirements. Some examples here。 这些数据库专为高吞吐量而设计。您还可以在 AWS 上查看它们的等效项。可能必须对您的数据进行一些非规范化以避免昂贵的(或明显不受支持的)连接。
我不确定更改数据库是否在这些问题的范围内,但缓存和数据库通常是可以实现最大性能改进的地方。
祝下次好运!