本文作者:啦啦啦啦啦,TiDB 老粉,现在上任于京东物流,社区资深用户,asktug 主页

一、背景

一般情况下运用 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: true
tikv:
readpool.coprocessor.use-unified-pool: true
readpool.storage.use-unified-pool: false
pd:
replication.enable-placement-rules: true
    replication.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 run
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_only --tables=1 --table-size=5000 run
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  select_random_points --tables=1 --table-size=5000 run
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  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 2743
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

三、功用比照

TiDB v6.0.0 (DMR) :缓存表初试丨TiDB Book Rush
TiDB v6.0.0 (DMR) :缓存表初试丨TiDB Book Rush
TiDB v6.0.0 (DMR) :缓存表初试丨TiDB Book Rush
TiDB v6.0.0 (DMR) :缓存表初试丨TiDB Book Rush

读写混合功用测验

测验首要场景参数 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

三、功用比照

TiDB v6.0.0 (DMR) :缓存表初试丨TiDB Book Rush
TiDB v6.0.0 (DMR) :缓存表初试丨TiDB Book Rush
TiDB v6.0.0 (DMR) :缓存表初试丨TiDB Book Rush
TiDB v6.0.0 (DMR) :缓存表初试丨TiDB Book Rush

五、遇到的问题

  • 测验将 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 中向研制大佬提出了这个问题得到了回答。依据 github.com/pingcap/tid… 中的描述,当机器负载较重时,load table 需求 3s 以上 ,可是默许的 tidb_table_cache_lease 是 3s, 表明加载的数据是立即过时的,因而需求重新加载,而且该过程永远重复。导致了浪费了很多的 CPU 资源而且下降了 QPS。现在能够将 tidb_table_cache_lease 的值调大来处理,该问题在 master 分支中现已处理,后续版别应该不会呈现。

依据测验成果,写入较为频频的情况下缓存表的功用是比较差的。在包括写恳求的测验中,缓存表相较于一般表的功用简直都大幅下降。

在 lease 过期之前,无法对数据履行修正操作。为了保证数据一致性,修正操作必须等待 lease 过期,所以会呈现写入推迟。例如 1tidb_table_cache_lease1 为 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 几种只读的场景下功用有非常大的提高,但在包括写恳求的测验中无法供给更好的功用。它的机制决议了运用场景现在仅限于表的数据量不大的只读表,或许简直很少修正的小表。综上,尽管缓存表现在的运用场景比较照较单一,可是在适宜的场景下确实是一个处理了事务痛点的好功用,也等待在后续的版别中能有更高的稳定性和更优秀的功用体现。