IT系统及PostgreSQL的伸缩(垂直扩展&水平扩展)

2020-06-17 00:00:00 事务 服务器 分区 服务 扩展

分布式系统的垂直扩展和水平扩展

高并发High Concurrency)是互联网分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计保证系统能够同时并行处理很多请求。提高系统并发能力的方式,方法论上主要有两种:垂直扩展(Scale Up)与水平扩展(Scale Out)。

垂直扩展:提升单机处理能力。垂直扩展的方式有:

  • 增强单机硬件性能。如:升级CPU算力和核数,升级更好的网卡如万兆,升级更好的硬盘如SSD,扩充硬盘如2T,扩充内存如128G;
  • 提升单机架构性能。如:使用Cache来减少IO次数,使用异步来增加单服务吞吐量,使用无锁数据结构来减少响应时间;

优点单机优化易于配置且维护和管理开销小,性能改善简单快捷;

缺点增强单机硬件的购置成本高,并且有可能效益不高;单机性能总是有极限的,所以互联网分布式架构设计高并发的终极解决方案还是水平扩展。

水平扩展:通过增加服务器数量,从而线性扩充系统性能。水平扩展对系统架构设计是有要求的。

  • 反向代理层的水平扩展:是通过“DNS轮询”实现的。dns-server对于一个域名配置了多个解析ip,每次DNS解析请求来访问dns-server,会轮询返回这些ip。

当nginx成为瓶颈的时候,只要增加服务器数量,新增nginx服务的部署,增加一个外网ip,就能扩展反向代理层的性能,做到理论上的无限高并发。

  • 站点层的水平扩展:是通过nginx实现的。通过修改nginx.conf,可以设置多个web后端。

当web后端成为瓶颈的时候,只要增加服务器数量,新增web服务的部署,在nginx配置中配置上新的web后端,就能扩展站点层的性能,做到理论上的无限高并发。

  • 服务层的水平扩展:是通过“服务连接池”实现的。

站点层通过RPC-client调用下游的服务层RPC-server时,RPC-client中的连接池会建立与下游服务多个连接,当服务成为瓶颈的时候,只要增加服务器数量,新增服务部署,在RPC-client处建立新的下游服务连接,就能扩展服务层性能,做到理论上的无限高并发。如果需要优雅的进行服务层自动扩容,这里可能需要配置中心里服务自动发现功能的支持。

  • 数据层的水平扩展(缓存、分库、分表)

在数据量很大的情况下,数据层(缓存,数据库)涉及数据的水平扩展,将原本存储在一台服务器上的数据(缓存,数据库)水平拆分到不同服务器上去,以达到扩充系统性能的目的。通常涉及:分布式集群、读写分离、读扩展、写扩展。

数据库作为应用请求的终点,对整体性能的影响很大,以下重点介绍PostgreSQL的水平扩展。

PostgreSQL的垂直扩展和水平扩展

PG垂直扩展方案

单机服务器系统垂直扩展的前提下,还可以对单机数据库性能调优[1]:如:数据库配置调优,使用vacuum进行GC,SQL查询语句AnalyzeExplain并优化,创建索引;

PG水平扩展方案

  • Pgpool II(一主多备,读、写分离,读扩展)

PgPool II 是客户端应用程序和PostgreSQL集群之间的中间件产品。Pgpool II通过负载平衡,将写入发送到主节点,并在备节点之间平衡读取语句,来提供水平可伸缩性。Pgpool II提供连接级别和语句级别的负载平衡;连接级别的负载平衡 Pgpool II 进程与备节点建立连接,该连接的所有读取均发送到备节点,而写入则发送到主节点。使用语句级连接(Pgpool II 4.1中提供),每个语句在备节点上实现负载均衡。

  • 基于PG声明式分区的分片

分片是基于PG声明式分区的。

PG声明式分区:在PG10中发布;在声明性分区之前,PG 使用表继承 和 plpgsql 触发器提供表分区。
直接使用声明式分区,可以将位于一个数据服务器上的一个主表拆分出多个子分区;插入主表中的行都将基于分区键被路由到所属分区中。
PG11 对声明性分区的性能进行了许多改进,包括分区修剪。分区修剪:是基于 WHERE 谓词提供的,旨在排除无关分区,将查询直接路由到特定分区。

分片:是一种在一个或多个外部服务器上,对表进行分区的能力。通过声明式分区可以将主表拆分为位于同一数据库服务器上的多个分区表。分片允许对表进行分区,并使分区子表位于外部外部服务器上,而主表位于用户创建分片父表的主节点上。分片表中使用的所有外部服务器都是PostgreSQL外部服务器,不支持其他异构外部服务器,如MongoDB,MySQL等。

--在主服务器上,创建主表
CREATE TABLE measurement (
    city_id         int not null,
    logdate         date not null,
    peaktemp        int,
    unitsales       int
) PARTITION BY RANGE (logdate);

--远程服务器上(shard_1),创建一个分区表(结构与主表相同)
CREATE TABLE measurement_year2019 (
    city_id         int not null,
    logdate         date not null,
    peaktemp        int,
    unitsales       int
) ;

--在主服务器上,给主表绑定外部服务器上的子分区表
CREATE TABLE measurement_year2019 PARTITION OF measurement
       FOR VALUES FROM('2019-01-01') TO ('2020-01-01')
Server shard_1;

相关文章