CPU 越多性能就会越好吗?

2021-09-26 17:26:03 浏览数 (1)

大多数情况是这样的,因为 CPU 可以提高运算速度。但这不是绝对的,假如我们的程序里有很多锁的概念,那就无法体现出多线程的多核性。那可能 CPU 的多少就不会有显著效果。一般遇到这种情况,许多公司会考虑把服务拆开。这就涉及到成本问题,也就是说增加 CPU 并不是最优解,我们还是需要考虑如何去优化锁。不过思考具体优化前我们可以先了解下池化技术。

上图是池化技术的抽象概念,一般获取连接以及线程用完后都会放入资源池资源池。同时我们还需要有以下四个概念:连接池、线程池、常量池、内存池。

一般用连接池较多,因为系统之间的调用、请求外部服务时都会通过请求连接来进行。曾经我们使用的是短连接,但是由于 HTTP 的每次连接都需要重复建立和关闭连接的过程,非常耗时,所以现在开始使用连接池。它每次请求完后创建的连接都是重复可用的,非常有助于节省开销。同时我们的任务最后都是需要拆出来的,而那些拆出来的异步任务则都放置在线程池内进行。常量池和内存池的概念是想通的,我们会申请一块大的内存复用。

了解池化技术后,我们回到具体优化。

应用架构优化

Web Server 优化

首先来看一下 Web Server 的优化,它主要通过代码优化、热点缓存、算法优化等等步骤实现。

第一步是代码优化,将不合理的代码进行优化。比如查询接口通常都会查询很多内容,使得运算缓慢,这就需要优先进行优化。

第二步是热点缓存,将全部的热点数据进行缓存从而尽可能减少数据库的操作。比如 Authing 身份认证在拿到 token 后不可能每次进行数据库运算,这样 QPS 会非常慢,我们可以通过将热点数据全部缓存来提高 QPS。

第三步是算法优化,因为我们的业务通常都非常复杂,所以这个概念非常广泛。比如查询一个列表,是需要一次性列出全部列表还是在内存中计算完毕后将结果返回给前端呢?这就需要针对不同的业务场景进行优化,从而提高性能。

单独部署

完成单体应用优化后,如果这些服务都部署在同一台服务器上,那可能会出现 CPU 和内存被占用的情况。这时候我们可以把 Web、以及加载完缓存的应用程序拎出来分别部署到一个单独服务器上。同时将静态资源全部存储在 CDN 上,通过就近访问加快页面加载速度。通过这些方式,让我们的 Auting 达到了 50 毫秒内响应的需求。单独部署的方式也非常适合系统之间的需求,无论你是什么业务场景,如果需要提升响应速度,那大家可以考虑这个方式。

垂直拆分

之后我们需要对业务进行拆分。业务拆分有以下三种方式:

  • 按照业务场景拆分,比如将用户、订单、账务进拆分。
  • 按照业务是同步还是异步进拆分,这样做的好处是可以很好控制异步流量,不让它影响我们的核心服务运行。
  • 按照模型拆分,因为业务拆分主要是为了解决系统之间耦合严重依懒性问题,为了后期尽量减少系统间的以来,所以前期的模型一定要尽可能的建设好。

在完成系统拆分后,我们需要评判优化后的系统能承载多少业务量,优化了多少。那么我就需要对它进行一次压测。压测会涉及到大家都有所了解的木桶理论,我们将系统比作一个木桶,那么木桶能够承载多少水量取决于最低的那块木板。所以压测时我们不需要关注那些占用资源少的部分,我们要关心那些高的已经达到了系统瓶颈的部分。通过这部分来查找我们系统的潜在问题点。

横向拆分

在我们将服务进行垂直拆分后,随着请求量逐渐增多可能还是无法满足需求。这时候我们可以将系统进行水平拆分,然后进行水平扩容,一个不够就增加两个甚至更多。同时通过负载均衡的服务器将请求量均匀分给这些水平节点。通常我们会选择使用 NG 来作负载均衡服务器。

上图是我们的负载均衡服务器。负载均衡下面会有很多网关系统,我们看到中间有一个 Nginx 集群。我们都知道 Nginx 能够承受的并发量非常大,所以流量小的时候不需要这个集群,需要它的时候一定是并发量非常大的情况。当你的并发量极大,到 Nginx 集群都无法承受的时候,我们最好不要在它的集群前面再放一层 Nginx,因为效果并不明显。同时我个人也不太建议大家选择 F5,因为 F5 是一个硬件,它的成本比较大。我个人建议大家选择 LVS,它是 Linux 下面的一个虚拟服务,如果配置的好,它的性能完全比得上 F5。

说完了负载均衡,我们回到水平拆分。

在进行水平拆分时我们不能忽略缓存问题。在单机模式下缓存都是本地缓存,而当我们成为分布式后,如果有一个服务器拿到 token 并存到本地,另一个服务器就会因为没有拿到而无法通信。因此我们引入分布式缓存,比如将缓存放到 Redis 这种分布式缓存里,让所有应用都请求 Redis 拿缓存。

当我们水平拆分后,还需要关注分布式 ID。因为单体时候生成 ID 的方法可能不适用于分布式服务。以时间戳举例,以前在单体时有,请求我们就生成一个 ID,这是有唯一性的。在分布式情况下多个服务器收到请求可能会生成重复 ID,做不到唯一性。所以我们需要单独做一个 ID 服务来生成 ID。

配置中心

在我们把服务进行了水平和垂直的拆分后,如何让配置统一同步的配置到每一个服务就成了问题。最好的办法就是当我们修改配置后,让所有服务都同时感知到这个更改,然后自己应用并配置。因此我们引入了配置中心。

上图是配置中心的大体流程,目前比较流行的配置中心方案有两个是,一个是阿里开源的 Nacos,另一个是 Spring Cloud 组建的 Spring Cloud config,感兴趣的朋友们可以了解一下。

接下来我们具体看一下上图。这其中 Server 是存放我们配置的控制台。一般开发者会在控制台通过 API 修改配置,修改后的配置可以持久放置在 Mysql 或其他数据库内。Client 包含了我们所有的应用,在它里面会有一个监听 Server 内是否有配置更改的监听,当有配置更改时则去获取这个配置,这样所有的应用就可以在前端更新后及时更新了。同时为了防止 App 在获取更新时因为网络问题而获取失败的情况,我们会在本地做一个快照,当网络出现问题时,App 可以降级到本地获取文件。

0 人点赞