TiDB v6.0.0(DMR) 缓存表初试

2023-10-11 01:59
文章标签 tidb 缓存 初试 v6.0 dmr

本文主要是介绍TiDB v6.0.0(DMR) 缓存表初试,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

\n> 原文来源: https://tidb.net/blog/452fe625 \n\n【是否原创】是

【首发渠道】TiDB 社区

【首发渠道链接】其他平台首发请附上对应链接

【正文】

一、背景

一般情况下使用 TiDB 单表大小为千万级别以上在业务中性能最优,但是在实际业务中总是会存在小表。例如配置表对写请求很少,而对读请求的性能的要求更高。TiDB 作为一个分布式数据库,大表的负载很容易利用分布式的特性分散到多台机器上,但当表的数据量不大,访问又特别频繁的情况下,数据通常会集中在 TiKV 的一个 Region 上,形成读热点,更容易造成性能瓶颈。

TiDB v6.0.0(DMR) 版本推出了缓存表的功能,第一次看到这个词的时候让我想到了 MySQL 的内存表。MySQL 内存表的表结构创建在磁盘上,数据存放在内存中。内存表的缺点很明显。当 MySQL 启动着的时候,表和数据都存在,当 MySQL 重启后,表结构存在,数据消失。TiDB 的缓存表不存在这个问题。从 asktug 论坛中看到很多小伙伴都很期待缓存表的表现,个人也对它的性能很期待,因此在测试环境中实际看看缓存表的性能如何。

二、缓存表的使用场景

以下部分内容来自官方文档,详情见 缓存表

TiDB 缓存表功能适用于以下特点的表:

  • 表的数据量不大
  • 只读表,或者几乎很少修改
  • 表的访问很频繁,期望有更好的读性能

关于第一点官方文档中提到缓存表的大小限制为包含索引在内的所有 key-value 记录的总大小不能超过 64 MB。实际测试使用 Sysbench 生成下文中表结构的表从 20w 提高到 30w 数据量时无法将普通表转换为缓存表,因此生产环境中实际使用缓存表的场景应该最多不超过几十万级别的数据量。关于缓存表对包含读写操作方面的性能,使用多种不同的读写请求比例进行了测试,相较普通表均没有达到更好的性能表现。这是因为为了读取数据的一致性,在缓存表上执行修改操作后,租约时间内写操作会被阻塞,最长可能出现 tidb_table_cache_lease 变量值时长的等待,会导致 QPS 降低。因此缓存表更适合只读表,或者几乎很少修改的场景。

缓存表把整张表的数据从 TiKV 加载到 TiDB Server 中,查询时可以不通过访问 TiKV 直接从 TiDB Server 的缓存中读取,节省了磁盘IO和网络带宽。使用普通表查询时,返回的数据量越多索引的效率可能越低,直到和全表扫描的代价接近优化器可能会直接选择全表扫描。缓存表本身数据都在 TiDB Server 的内存中,可以避免磁盘 IO,因此查询效率也会更高。以配置表为例,当业务重启的瞬间,全部业务连接一起加载配置,会造成较高的数据库读延迟。如果使用了缓存表,读请求可以直接从内存中读取数据,可以有效降低读延迟。在金融场景中,业务通常会同时涉及订单表和汇率表。汇率表通常不大,表结构很少发生变化因此几乎不会有 DDL,加上每天只更新一次,也非常适合使用缓存表。其他业务场景例如银行分行或者网点信息表,物流行业的城市、仓号库房号表,电商行业的地区、品类相关的字典表等等,对于这种很少新增记录项的表都是缓存表的典型使用场景。

三、测试环境

1.硬件配置及集群拓扑规划

使用 2 台云主机,硬件配置为 4C 16G 100G 普通 SSD 硬盘。

Role Host Ports
alertmanager 10.0.0.1 9093/9094
grafana 10.0.0.1 3000
pd 10.0.0.1 2379/2380
pd 10.0.0.2 2379/2380
pd 10.0.0.1 3379/3380
prometheus 10.0.0.1 9090/12020
tidb 10.0.0.1 4000/10080
tidb 10.0.0.2 4000/10080
tikv 10.0.0.1 20162/20182
tikv 10.0.0.1 20160/20180
tikv 10.0.0.2 20161/20181
2. 软件配置
软件名称 软件用途 版本
CentOS 操作系统 7.6
TiDB 集群 开源分布式 NewSQL 数据库 v6.0.0 DMR
Sysbench 压力测试工具 1.0.20
3.参数配置
server_configs:
tidb:
log.slow-threshold: 300
new_collations_enabled_on_first_bootstrap: truetikv:
readpool.coprocessor.use-unified-pool: true
readpool.storage.use-unified-pool: false
pd:
replication.enable-placement-rules: truereplication.location-labels:- host

由于硬件条件受限,只有 2 台普通性能的云主机混合部署的集群(实际上和单机部署也差不多了)。单机 CPU 核数较少且 TiDB Server 没有做负载均衡所以并发无法调整太高。以下测试均使用一个 TiDB Server 节点进行压测,因此不用特别关注本次测试的测试数据,可能会跟其他测试结果有所出入,不代表最佳性能实践和部署,测试结果仅限参考。

四、性能测试

Sysbench 生成的表结构

CREATE TABLE sbtest1 (
id int(11) NOT NULL AUTO_INCREMENT,
k int(11) NOT NULL DEFAULT '0',
c char(120) NOT NULL DEFAULT '',
pad char(60) NOT NULL DEFAULT '',
PRIMARY KEY (id),
KEY k_1 (k)
) ENGINE = InnoDB CHARSET = utf8mb4 COLLATE = utf8mb4_bin AUTO_INCREMENT = 1

读性能测试

测试主要参数

oltp_point_select 主键查询测试(点查,条件为唯一索引列)

主要 SQL 语句:

SELECT c FROM sbtest1 WHERE id=?

select_random_points 随机多个查询(主键列的 selete in 操作)

主要 SQL 语句:

SELECT id, k, c, pad FROM sbtest1 WHERE k IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)

select_random_ranges 随机范围查询(主键列的 selete between and 操作)

主要 SQL 语句:

SELECT count(k) FROM sbtest1 WHERE k BETWEEN ? AND ? OR k BETWEEN ? AND ? OR k BETWEEN ? AND ? OR k BETWEEN ? AND ? OR k BETWEEN ? AND ? OR k BETWEEN ? AND ? OR k BETWEEN ? AND ? OR k BETWEEN ? AND ? OR k BETWEEN ? AND ? OR k BETWEEN ? AND ?

oltp_read_only 只读操作(包含聚合、去重等)

主要 SQL 语句:

SELECT c FROM sbtest1 WHERE id=?

SELECT SUM(k) FROM sbtest1 WHERE id BETWEEN ? AND ?

SELECT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c

SELECT DISTINCT c FROM sbtest1 WHERE id BETWEEN ? AND ? ORDER BY c

Sysbench 测试命令示例
sysbench --mysql-host=10.0.0.1  --mysql-port=4000  --mysql-db=sbtest --mysql-user=root --time=600 \
--threads=8 --report-interval=10 --db-driver=mysql  oltp_point_select --tables=1 --table-size=5000 runsysbench --mysql-host=10.0.0.1  --mysql-port=4000  --mysql-db=sbtest --mysql-user=root --time=600 \
--threads=8 --report-interval=10 --db-driver=mysql  oltp_read_only --tables=1 --table-size=5000 runsysbench --mysql-host=10.0.0.1  --mysql-port=4000  --mysql-db=sbtest --mysql-user=root --time=600 \
--threads=8 --report-interval=10 --db-driver=mysql  select_random_points --tables=1 --table-size=5000 runsysbench --mysql-host=10.0.0.1  --mysql-port=4000  --mysql-db=sbtest --mysql-user=root --time=600 \
--threads=8 --report-interval=10 --db-driver=mysql  select_random_ranges --tables=1 --table-size=5000 run
一、使用普通表
1.单表数据量 5000,测试 QPS
threads/request type oltp_point_select oltp_read_only select_random_points select_random_ranges
8 2214 1985 3190 2263
16 3199 2414 3412 2491
32 4454 2867 3898 2763
64 5792 3712 4321 2981
128 7639 4964 4474 2965
2.单表数据量 50000,测试 QPS
threads/request type oltp_point_select oltp_read_only select_random_points select_random_ranges
8 4874 2808 2841 2207
16 5042 3429 3172 2448
32 6754 4290 3405 2651
64 8989 5282 3831 2818
128 12565 6470 3996 2811

| |

二、使用缓存表
1.单表数据量 5000,测试 QPS
threads/request type oltp_point_select oltp_read_only select_random_points select_random_ranges
8 15780 10811 5666 2716
16 23296 11399 6417 2948
32 28038 11313 6907 3050
64 32924 11377 7217 3200
128 33962 11413 7199 3232
2.单表数据量 50000,测试 QPS
threads/request type oltp_point_select oltp_read_only select_random_points select_random_ranges
8 15910 16540 5359 2646
16 21945 17022 5999 2915
32 25614 17356 6355 3065
64 31782 17410 6690 3088
128 35009 17584 6713 3161
三、性能对比

image.png

image.png

image.png

image.png

读写混合性能测试

测试主要场景参数

oltp_read_write 表示混合读写。

point_selects(每个事务里点查的数量)

delete_inserts(每个事务里插入/删除组合的数量)

主要 SQL 语句:

INSERT INTO sbtest1 (id, k, c, pad) VALUES (?, ?, ?, ?)

DELETE FROM sbtest1 WHERE id=?

SELECT c FROM sbtest1 WHERE id=?

本次测试通过单个事务中请求类型的数量 --delete_inserts 固定为 10 且调整 --point_selects 参数的值来模拟不同读写比例下的性能差异,其余请求参数使用默认值,具体命令可参考下面 Sysbench 测试命令示例。

Sysbench 测试命令示例
sysbench --mysql-host=10.0.0.1  --mysql-port=4000  --mysql-db=sbtest --mysql-user=root --time=600 --threads=8 --report-interval=10 --db-driver=mysql  oltp_read_write --tables=1 --table-size=5000   --point_selects=10 --non_index_updates=0 --delete_inserts=10 --index_updates=0 run
一.使用普通表
1.单表数据量 5000,测试 QPS
threads/--point_selects 10 40 160 640
8 869 2289 3852 5090
16 1014 2139 4354 6094
32 1075 2205 5089 6944
64 605 1861 5160 8395
128 877 2127 4332 9257
2.单表数据量 50000,测试 QPS
threads/--point_selects 10 40 160 640
8 1107 2144 3312 4439
16 1108 2103 3738 5702
32 1055 2228 4325 6770
64 1062 1397 5367 8209
128 981 1838 7235 17472
二、使用缓存表
1.单表数据量 5000,测试 QPS

| threads/--point_selects | 10 | 40 | 160 | 640 | | -----------------------: | --: | ---: | ---: | ---: | | 8 | 711 | 1322 | 2123 | 2787 | | 16 | 361 | 665 | 1274 | 2870 | | 32 | 400 | 627 | 1394 | 2997 | | 64 | 323 | 804 | 1853 | 4100 | | 128 | 372 | 680 | 1847 | 4704 |

2.单表数据量 50000,测试 QPS

| threads/--point_selects | 10 | 40 | 160 | 640 | | -----------------------: | --: | ---: | ---: | ---: | | 8 | 974 | 2726 | 3716 | 1804 | | 16 | 787 | 1366 | 1736 | 2176 | | 32 | 673 | 1231 | 2338 | 4627 | | 64 | 572 | 1384 | 3120 | 7755 | | 128 | 557 | 1104 | 2907 | 7486 |

三、性能对比

image.png

image.png

image.png

image.png

五、遇到的问题

  • 尝试将 30w 数据的表改为缓存表时报错 ERROR 8242 (HY000): 'table too large' is unsupported on cache tables

目前 TiDB 对于每张缓存表的大小限制为 64 MB,因此太大的表无法缓存在内存中。另外,缓存表无法执行普通的 DDL 语句。若要对缓存表执行 DDL 语句,需要先使用 ALTER TABLE xxx NOCACHE 语句去掉缓存属性,将缓存表设回普通表后,才能对其执行其他 DDL 语句。

  • 测试过程中缓存表性能出现了不稳定的情况,有些时候缓存表反而比普通表读取性能差,使用 trace 语句( TRACE SELECT * FROM sbtest1; )查看发现返回结果中出现了 regionRequest.SendReqCtx ,说明 TiDB 尚未将所有数据加载到内存中,多次尝试均未加载完成。把 tidb_table_cache_lease 调整为 10 后没有出现该问题。

在 asktug 中向研发大佬提出了这个问题得到了解答。根据 https://github.com/pingcap/tidb/issues/33167 中的描述,当机器负载较重时,load table 需要 3s 以上 ,但是默认的 tidb_table_cache_lease 是 3s, 表示加载的数据是立即过时的,因此需要重新加载,并且该过程永远重复。导致了浪费了大量的 CPU 资源并且降低了 QPS。目前可以将 tidb_table_cache_lease 的值调大来解决,该问题在 master 分支中已经解决,后续版本应该不会出现。

  • 根据测试结果,写入较为频繁的情况下缓存表的性能是比较差的。在包含写请求的测试中,缓存表相较于普通表的性能几乎都大幅下降。

在 lease 过期之前,无法对数据执行修改操作。为了保证数据一致性,修改操作必须等待 lease 过期,所以会出现写入延迟。例如 tidb_table_cache_lease 为 10 时,写入可能会出现较大的延迟。因此写入比较频繁或者对写入延迟要求很高的业务不建议使用缓存表。

六、测试总结

读性能

单表 5000,缓存表相比普通表提升的百分比

threads/request type oltp_point_select oltp_read_only select_random_points select_random_ranges
8 612.73% 444.63% 77.61% 20.01%
16 628.22% 372.20% 88.01% 18.34%
32 529.50% 294.59% 77.19% 10.38%
64 468.43% 206.49% 67.02% 7.34%
128 344.58% 129.91% 60.90% 9.00%

单表 50000,缓存表相比普通表提升的百分比

threads/request type oltp_point_select oltp_read_only select_random_points select_random_ranges
8 226.42% 489.03% 88.63% 19.89%
16 335.24% 396.41% 89.12% 19.07%
32 279.24% 304.56% 86.63% 15.61%
64 253.56% 229.60% 74.62% 9.58%
128 178.62% 171.77% 67.99% 12.45%

读写混合

单表 5000,缓存表相比普通表提升的百分比(负增长符合预期)

threads/--point_selects 10 40 160 640
8 -35.77% -42.24% -44.88% -45.24%
16 -64.39% -68.91% -70.73 -52.90%
32 -62.79% -71.56% -72.60% -56.84%
64 -46.61% -42.44% -64.08% -50.05%
128 -57.58% -68.03% -57.36% -49.18%

单表 50000,缓存表相比普通表提升的百分比(负增长符合预期)

threads/--point_selects 10 40 160 640
8 -12.01% 27.14% 12.19% -59.36%
16 -28.97% -35.04% -53.55% -61.83%
32 -36.20% -44.74% -45.94% -31.65%
64 -46.13% -0.93% -41.86% -5.53%
128 -43.21% -39.93% -59.82% -57.15%

结果显示,相比于普通表,缓存表在 oltp_point_select、oltp_read_only、select_random_points、select_random_ranges 几种只读的场景下性能有非常大的提升,但在包含写请求的测试中无法提供更好的性能。它的机制决定了使用场景目前仅限于表的数据量不大 的只读表,或者几乎很少修改的小表。综上,虽然缓存表目前的使用场景相对比较单一,但是在合适的场景下确实是一个解决了业务痛点的好功能,也期待在后续的版本中能有更高的稳定性和更优秀的性能表现。

这篇关于TiDB v6.0.0(DMR) 缓存表初试的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/184717

相关文章

Golang基于内存的键值存储缓存库go-cache

《Golang基于内存的键值存储缓存库go-cache》go-cache是一个内存中的key:valuestore/cache库,适用于单机应用程序,本文主要介绍了Golang基于内存的键值存储缓存库... 目录文档安装方法示例1示例2使用注意点优点缺点go-cache 和 Redis 缓存对比1)功能特性

MySQL8.0设置redo缓存大小的实现

《MySQL8.0设置redo缓存大小的实现》本文主要在MySQL8.0.30及之后版本中使用innodb_redo_log_capacity参数在线更改redo缓存文件大小,下面就来介绍一下,具有一... mysql 8.0.30及之后版本可以使用innodb_redo_log_capacity参数来更改

MySQL 缓存机制与架构解析(最新推荐)

《MySQL缓存机制与架构解析(最新推荐)》本文详细介绍了MySQL的缓存机制和整体架构,包括一级缓存(InnoDBBufferPool)和二级缓存(QueryCache),文章还探讨了SQL... 目录一、mysql缓存机制概述二、MySQL整体架构三、SQL查询执行全流程四、MySQL 8.0为何移除查

Redis缓存问题与缓存更新机制详解

《Redis缓存问题与缓存更新机制详解》本文主要介绍了缓存问题及其解决方案,包括缓存穿透、缓存击穿、缓存雪崩等问题的成因以及相应的预防和解决方法,同时,还详细探讨了缓存更新机制,包括不同情况下的缓存更... 目录一、缓存问题1.1 缓存穿透1.1.1 问题来源1.1.2 解决方案1.2 缓存击穿1.2.1

Redis与缓存解读

《Redis与缓存解读》文章介绍了Redis作为缓存层的优势和缺点,并分析了六种缓存更新策略,包括超时剔除、先删缓存再更新数据库、旁路缓存、先更新数据库再删缓存、先更新数据库再更新缓存、读写穿透和异步... 目录缓存缓存优缺点缓存更新策略超时剔除先删缓存再更新数据库旁路缓存(先更新数据库,再删缓存)先更新数

el-select下拉选择缓存的实现

《el-select下拉选择缓存的实现》本文主要介绍了在使用el-select实现下拉选择缓存时遇到的问题及解决方案,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录项目场景:问题描述解决方案:项目场景:从左侧列表中选取字段填入右侧下拉多选框,用户可以对右侧

SpringBoot使用注解集成Redis缓存的示例代码

《SpringBoot使用注解集成Redis缓存的示例代码》:本文主要介绍在SpringBoot中使用注解集成Redis缓存的步骤,包括添加依赖、创建相关配置类、需要缓存数据的类(Tes... 目录一、创建 Caching 配置类二、创建需要缓存数据的类三、测试方法Spring Boot 熟悉后,集成一个外

使用Spring Cache时设置缓存键的注意事项详解

《使用SpringCache时设置缓存键的注意事项详解》在现代的Web应用中,缓存是提高系统性能和响应速度的重要手段之一,Spring框架提供了强大的缓存支持,通过​​@Cacheable​​、​​... 目录引言1. 缓存键的基本概念2. 默认缓存键生成器3. 自定义缓存键3.1 使用​​@Cacheab

Nacos客户端本地缓存和故障转移方式

《Nacos客户端本地缓存和故障转移方式》Nacos客户端在从Server获得服务时,若出现故障,会通过ServiceInfoHolder和FailoverReactor进行故障转移,ServiceI... 目录1. ServiceInfoHolder本地缓存目录2. FailoverReactorinit

缓存雪崩问题

缓存雪崩是缓存中大量key失效后当高并发到来时导致大量请求到数据库,瞬间耗尽数据库资源,导致数据库无法使用。 解决方案: 1、使用锁进行控制 2、对同一类型信息的key设置不同的过期时间 3、缓存预热 1. 什么是缓存雪崩 缓存雪崩是指在短时间内,大量缓存数据同时失效,导致所有请求直接涌向数据库,瞬间增加数据库的负载压力,可能导致数据库性能下降甚至崩溃。这种情况往往发生在缓存中大量 k