谈谈PolarDB-X在读写分离场景的实践

本文涉及的产品
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
云原生数据库 PolarDB MySQL 版,通用型 2核8GB 50GB
简介: 针对写少读多的业务可以考虑通过添加数据库节点来使其达到提升性能的目的,但添加节点,往往涉及到数据的搬迁,扩容周期比较长,很难应对徒增的业务流量,这个时候可以考虑采用读写分离的方式,将读写流量做分流,减轻主实例的压力,同时利用只读库横向的扩展能力,快速提升读性能。

在数据库使用过程中经常会遇到一些场景:

  1. 业务写流量一直相对比较稳定,但随着时间,数据不断增加,数据库的压力也会越来越大,写操作会影响到读请求的性能,做任何优化可能都达不到最终的效果;
  2. 在应用的用户访问量比较低的时候,一个数据库的读写能力是完全能够胜任的。但是在用户访问量增大的时候,数据库很快会成为瓶颈;

针对这种写少读多的业务可以考虑通过添加数据库节点来使其达到提升性能的目的,但添加节点,往往涉及到数据的搬迁,扩容周期比较长,很难应对徒增的业务流量。这个时候可以考虑采用读写分离的方式,将读写流量做分流,减轻主实例的压力,同时利用只读库横向的扩展能力,快速提升读性能。

其基本原理是让主数据库处理事务性查询,而从数据库处理select查询。当业务量非常大时,一台服务器的性能无法满足需求,就可以读写分离方式分摊负载,避免因负载太高而造成无法及时响应请求。目前业界实现读写分离的方案主要有两种:

基于程序代码内部实现
在代码中根据select,insert进行路由分类,这类方法也是目前生产环境应用最广泛的,优点是性能好,因为在程序代码中已经将读写的数据源拆分至两个,所以不需要额外的MySQL proxy解析SQL报文,在进行路由至不同数据库节点。缺点是通常该架构较复杂,运维成本相对较高。

基于中间Proxy(odp/mycat等)实现

Proxy一般位于客户端和服务器之间,代理服务器接到客户端请求后通过解析SQL文本再将SQL路由至可用的数据库节点中。优点是程序不需要改造可以实现无缝迁移,可移植性较好。缺点是性能相对前者略微逊色一些,并且并不是所有的读操作都能够被路由至从节点中。

上述方案都不能算是透明的,要不需要对业务代码进行改造,要不需要业务系统依然第三方组件;除此之外,业界主流的读写方案都无法做到一致性读,应用在使用弱一致性读时,要充分考虑主备副本的数据同步延时,并根据具体业务场景考虑延时的业务影响(脏读)是否能够接受。读写分离业务都还需要做额外的改造,以应对只读库异常或者延迟过大的时候下,对业务做降级处理。

为此,PolarDB-X内核侧提出一种提供了透明的强一致的读写分离能力,支持多种读写分离策略满足各类业务需求。

PolarDB-X Native 读写分离

PolarDB-X配置了多种读写策略,提供了透明的强一致的读写分离能力。简单的说其特点有:

  • 无论什么状况都不用担心误写了“备副本或只读副本”,因为它不支持写,写操作会被路由到主副本;
  • 无论什么时候不用担心“备副本或只读副本”故障,因为它会自动路由给其他正常的副本或者切回主副本;
  • 无论什么场景不用担心 “备副本或只读副本”读不到最新的数据,因为它提供的是强一致的读写能力;
  • 大查询不用担心打爆“主副本”,因为它支持将大查询路由给”备副本或只读副本“,避免对主副本造成压力。

其整体的方案设计如下:

PolarDB-X存储节点基于X-Paxos复制协议,整合了binary log,实现了统一的consensus log。consensus log不仅扮演了binary log的角色,同时还维护了LogIndex(全局一致性日志位点)。LogIndex中记录了主库了最新修改consensus log位点信息,当只读库做一致性复制的时候,也会不断更新自身的LogIndex信息。通过LogIndex我们可以确保在只读库上读到最新的数据,结合TSO可以确保读到已提交的一致性数据。路由到只读节点的强一致性读查询过程如下:

  1. 客户端把请求发送到CN;
  2. CN识别到请求会发送给只读实例,首先会从主实例DN节点获取当前最大LogIndex;
  3. CN把LogIndex +TSO  请求一起发送给只读节点;
  4. 只读节点根据接收到的LogIndex判断是否等到只读节点事务状态回放到相应位点;根据TSO判断数据可见性,给CN返回结果。

同时为了降低每次一次只读查询都会分别与主库交互获取LogIndex,我们为此做了异步Grouping Fetch Logindex优化,在高并发下尽可能将多次Fetch Logindex整合成一次请求,大大降低对主库的压力。

读写分离的操作管理

业务上不需要做任何改造,在需要的时候购买只读实例,默认情况下主实例就具备了读写分离的能力。如果要开启,需要在阿里控制台点击主实例上的集群地址-》配置管理。

会进入下只读分离的配置管理页面

操作

解释

资源配置

选择购买的只读实例加入到读写分离集群,只有在读写分离集群的实例才可以分担主实例的流量

智能读写分离

基于统计信息做代价估算,将偏AP的复杂查询路由给只读实例做MPP加速。非混合负载场景,可以选择关闭

只读流量占比

将只读流量设置按一定的比例路由给只读实例

数据一致性

强一致性: 路由到只读实例的请求可以读到已提交最新鲜的数据,但如果只读实例延迟大的话,路由到只读实例

弱一致性: 路由到只读实例的请求只是读到实例上可见的最新数据。

只读实例延迟阀值

只读实例延迟超过阈值,那么流量会打到其他延迟正常的只读实例上或者切回主实例。

只读可用性

当只读实例延迟超过阈值或者只读实例 HA时,则认为当前只读实例处于不可用的状态,流量自动切回主实例或者其他正常的只读实例上去。

用户真正在使用的时候,业务上完全不需要改造任何代码,一般只需要调整只读流量占比,调整为0意味着流量全部路由给主库;调整成>0,只读流量将按照设置的比例自动分流给只读实例。在这个基础上结合只读实例延迟阀值只读可用性,可以做到在只读实例异常状态下,流量自动切回主实例或者其他正常的只读实例上去。除了数据库级别的配置,PolarDB-X也支持session级别和query级别的读写配置,可灵活控制某个session下只读查询或者某个具体query的路由分发。

读写分离的可用性测试

为了衡量PolarDB-X 读写分离能力的可用性,我们利用sysbench 从正确性 性能角度设计了三种实验场景来验证。

测试环境

  • 测试所用实例规格

主实例规格2*16C128G (CN)+2*4C32G(DN), 2个只读实例规格  2*4C32G(CN) +  2*4C 32G(DN)

  • 测试所用压力机规格

ecs.g7ne.8xlarge(24 vCPU,48 GB内存)

测试参数配置

  • 修改参数ENABLE_COROUTINE的值为true,XPROTO_MAX_DN_CONCURRENT的值为4000,详细操作步骤请参见参数设置。
  • 通过命令行连接到PolarDB-X实例,在同一会话内执行如下SQL语句,关闭日志记录与CPU采样统计:

set ENABLE_SET_GLOBAL = true;

set global RECORD_SQL = false;

set global MPP_METRIC_LEVEL = 0;

set global ENABLE_CPU_PROFILE = false;

测试数据准备

nohup sysbench --config-file='sysb.conf' --create-table-options='partition by key(id)'  --tables='16' --threads='16' --table-size='10000000' oltp_point_select prepare &


实验一:一致性读的正确性

从附件中下载这次测试的oltp_insert_read_verify.lua脚本,该脚本逻辑比较简单,就是在主实例插入一条数据,测试在不同并发下在一致性读开启和关闭条件下,是否可以正确读到。一次实验的执行流程如下:


#准备表

sysbench --config-file='sysb.conf' --db-ps-mode='disable' --skip-trx='on' --mysql-ignore-errors='all' --tables='8' --threads={并发度} --time=60 oltp_insert_read_verify prepare


#运行

sysbench --config-file='sysb.conf' --db-ps-mode='disable' --skip-trx='on' --mysql-ignore-errors='all' --tables='8' --threads={并发度} --time=60 oltp_insert_read_verify run


#清理

sysbench --config-file='sysb.conf' --db-ps-mode='disable' --skip-trx='on' --mysql-ignore-errors='all' --tables='8' --threads={并发度} --time=60 oltp_insert_read_verify cleanup


测试结果

并发

不一致性次数(弱一致性读)

不一致性次数(强一致性读)

4

2

0

8

5

0

16

16

0

32

33

0

64

57

0

从测试结果看,强一致性读下,可以保证路由到只读实例的流量读到最新的数据;而非强一致性读下,无法保证。


实验二:高并发下吞吐表现

我们分别利用oltp_point_select和oltp_read_only两个脚本,测试了下在当前规格下高并发下的性能数据。


  • 点查场景

sysbench --config-file='sysb.conf' --db-ps-mode='disable' --skip-trx='on' --mysql-ignore-errors='all' --tables='16' --table-size='10000000' --threads=512  oltp_point_select run

测试了在不同只读实例个数,不同配置下的性能数据,其QPS表现如下

只读实例查询占比

主实例+一个只读实例(强一致性)

主实例+一个只读实例(弱一致性)

主实例+两个只读实例(强一致性)

主实例+两个只读实例(弱一致性)

0%

88201.17

88201.17

88201.17

88201.17

50%

124269.63

171935.56

171783.84

208648.34

100%

62891.86

89213.13

117133.83

169352.07


  • oltp_read场景

sysbench --config-file='sysb.conf' --db-ps-mode='disable' --skip-trx='on' --mysql-ignore-errors='all' --tables='16' --table-size='10000000' --range-size=5 --threads=512 oltp_read_only run

测试了在不同只读实例个数,不同配置下的性能数据,其QPS表现如下

只读实例查询占比

主实例+一个只读实例(强一致)

主实例+一个只读实例(弱一致)

主实例+两个只读实例(强一致)

主实例+两个只读实例(弱一致)

0%

29145.43

29145.43

29145.43

29145.43

50%

44084.40

55399.80

61698.85

73161.11

100%

23115.23

29235.73

42160.54

56393.54


从测试结果看:

1. 在强一致性读下,在TP读场景下流量从主实例切换到只读实例上吞吐的性能衰减20~30%,但是通过添加只读实例个数,性能可以做到一定的线性增加;

2.在弱一致性读下,在TP读场景下流量从主实例切换到只读实例上吞吐的性能未衰减,且通过添加只读实例的个数,性能可以做到线性增加;


实验三:低并发下RT表现

同样的我们分别利用oltp_point_select和oltp_read_only两个脚本,测试了下在(一个主实例+只读实例)下在强一致性读条件下,不同并发的RT表现。


  • 点查场景(ms)

并发

只读查询比例0%

只读查询比例100%

只读查询比例50%

4

0.61

0.89

0.87

8

0.62

0.91

0.89

16

0.64

0.94

0.90

32

0.71

1.04

0.99

64

1.18

1.27

1.27


  • oltp_read场景(ms)

并发

只读查询比例0%

只读查询比例100%

只读查询比例50%

4

11.65

21.89

17.63

8

12.21

22.69

17.29

16

14.21

23.95

18.23

32

20

27.17

21.50

64

40.5

50.7

31.37


从测试结果看:

  1. 低并发场景下,只读实例和主实例压力都不大,流量从主实例切换到只读实例上,RT衰减近30%~40%, 但都是在业务可以接受的RT范围内抖动;
  2. 随着并发增加,流量从主实例切换到只读实例上RT衰减会变得不明显,主实例的资源会成为影响RT的主要因素。


本文的读写分离路由的是非事务下的只读流量,这里给大家提一个问题:事务下的读查询是否可以做读写分离?

📎oltp_insert_read_verify.lua

相关文章
|
7月前
|
关系型数据库 分布式数据库 数据库
一库多能:阿里云PolarDB三大引擎、四种输出形态,覆盖企业数据库全场景
PolarDB是阿里云自研的新一代云原生数据库,提供极致弹性、高性能和海量存储。它包含三个版本:PolarDB-M(兼容MySQL)、PolarDB-PG(兼容PostgreSQL及Oracle语法)和PolarDB-X(分布式数据库)。支持公有云、专有云、DBStack及轻量版等多种形态,满足不同场景需求。2021年,PolarDB-PG与PolarDB-X开源,内核与商业版一致,推动国产数据库生态发展,同时兼容主流国产操作系统与芯片,获得权威安全认证。
|
9月前
|
关系型数据库 分布式数据库 PolarDB
PolarDB 开源基础教程系列 7.2 应用实践之 跨境电商场景
本文介绍了如何在跨境电商场景中快速判断商标或品牌侵权,避免因侵权带来的法律纠纷。通过创建品牌表并使用PostgreSQL的pg_trgm插件和GIN索引,实现了高性能的字符串相似匹配功能。与传统方法相比,PolarDB|PostgreSQL的方法不仅提升了上万倍的查询速度,还解决了传统方法难以处理的相似问题检索。具体实现步骤包括创建品牌表、插入随机品牌名、配置pg_trgm插件及索引,并设置相似度阈值进行高效查询。此外,文章还探讨了字符串相似度计算的原理及应用场景,提供了进一步优化和扩展的方向。
264 11
|
9月前
|
SQL 关系型数据库 分布式数据库
PolarDB 开源基础教程系列 7.5 应用实践之 TPCH性能优化
PolarDB在复杂查询、大数据量计算与分析场景的测试和优化实践.
307 7
|
9月前
|
搜索推荐 关系型数据库 分布式数据库
PolarDB 开源基础教程系列 7.3 应用实践之 精准营销场景
本文介绍了基于用户画像的精准营销技术,重点探讨了如何通过标签组合快速圈选目标人群。实验分为三部分: 1. **传统方法**:使用字符串存储标签并进行模糊查询,但性能较差,每次请求都需要扫描全表。 2. **实验1**:引入`pg_trgm`插件和GIN索引,显著提升了单个模糊查询条件的性能。 3. **实验2**:改用数组类型存储标签,并结合GIN索引加速包含查询,性能进一步提升。 4. **实验3**:利用`smlar`插件实现近似度过滤,支持按标签重合数量或比例筛选。
190 3
|
5月前
|
关系型数据库 MySQL 分布式数据库
Super MySQL|揭秘PolarDB全异步执行架构,高并发场景性能利器
阿里云瑶池旗下的云原生数据库PolarDB MySQL版设计了基于协程的全异步执行架构,实现鉴权、事务提交、锁等待等核心逻辑的异步化执行,这是业界首个真正意义上实现全异步执行架构的MySQL数据库产品,显著提升了PolarDB MySQL的高并发处理能力,其中通用写入性能提升超过70%,长尾延迟降低60%以上。
|
9月前
|
Cloud Native 关系型数据库 分布式数据库
客户说|信美相互人寿携手阿里云PolarDB,引领保险IFRS17场景创新
客户说|信美相互人寿携手阿里云PolarDB,引领保险IFRS17场景创新
249 2
|
9月前
|
人工智能 关系型数据库 分布式数据库
PolarDB 开源基础教程系列 7.4 应用实践之 AI大模型外脑
PolarDB向量数据库插件通过实现通义大模型AI的外脑,解决了通用大模型无法触达私有知识库和产生幻觉的问题。该插件允许用户将新发现的知识和未训练的私有知识分段并转换为向量,存储在向量数据库中,并创建索引以加速相似搜索。当用户提问时,系统将问题向量化并与数据库中的向量进行匹配,找到最相似的内容发送给大模型,从而提高回答的准确性和相关性。此外,PolarDB支持多种编程语言接口,如Python,使数据库具备内置AI能力,极大提升了数据处理和分析的效率。
387 4
|
10月前
|
存储 SQL 缓存
PolarDB-X 在 ClickBench 数据集的优化实践
本文介绍了 PolarDB-X 在 ClickBench 数据集上的优化实践,PolarDB-X 通过增加优化器规则、优化执行器层面的 DISTINCT 和自适应两阶段 AGG、MPP 压缩等手段,显著提升了在 ClickBench 上的性能表现,达到了业内领先水平。
|
安全 druid Java
Seata 1.8.0 正式发布,支持达梦和 PolarDB-X 数据库
Seata 1.8.0 正式发布,支持达梦和 PolarDB-X 数据库
1210 94
Seata 1.8.0 正式发布,支持达梦和 PolarDB-X 数据库
|
存储 DataWorks 监控
DataWorks,一个 polar db 有上万个数据库,解决方案
DataWorks,一个 polar db 有上万个数据库,解决方案

相关产品

  • 云原生数据库 PolarDB
  • 下一篇
    oss云网关配置