RDS MySQL提供阿里云自研的X-Engine存储引擎,支持事务并且可以大幅降低磁盘空间占用。
产品介绍
X-Engine是阿里云数据库产品事业部自研的联机事务处理OLTP(On-Line Transaction Processing)数据库存储引擎。作为自研数据库PolarDB的存储引擎之一,已经广泛应用在阿里集团内部诸多业务系统中,包括交易历史库、钉钉历史库等核心应用,大幅缩减了业务成本,同时也作为双十一大促的关键数据库技术,挺过了数百倍平时流量的冲击。
X-Engine是适用于大规模电子商务交易处理的优化存储引擎,X-Engine团队撰写的论文 《X-Engine: An Optimized Storage Engine for Large-scale E-Commerce Transaction Processing》,详细讲述了X-Engine在数据库存储引擎领域所做的原创性工作,2019年被SIGMOD'19 Industrial Track接收。
与传统的InnoDB引擎不同,X-Engine使用分层存储架构(LSM-Tree)。分层存储有两个比较显著的优点:
需要索引的热点数据集更小,写入性能更高。
底层持久化的数据页是只读的,数据页采用紧凑存储格式,同时默认进行压缩,存储成本更低。
除了LSM-Tree架构自身的优势之外,X-Engine在工程实现上也进行了大量的创新,主要包含如下几个方面:
利用先天性的优势,持续优化写入性能,X-Engine相比同为LSM-tree架构的Rocksdb,有超过10倍的性能提升。
在存储层引入数据复用技术等,优化Compaction的性能,降低传统LSM-tree架构中Compaction动作对系统资源的冲击,保持系统性能平稳。
支持在同一实例中混合部署SSD/HDD等不同IO能力的存储设备, 利用天然分层结构的特点,结合不同存储硬件的IO读写性能,智能地进行数据的冷热分离存储,在不降低性能的前提下,降低综合成本。
引入多个层级Cache,同时结合Cach回填和预取机制,利用精细化访问机制和缓存技术,弥补传统LSM-tree引擎的读性能短板。
通过以上多方面的工程优化,X-Engine成为传统InnoDB引擎的一个替代选项,既支持事务,同时又能够显著的降低业务存储成本(依据数据特征,存储空间可降低至10%~50%),特别适合数据容量巨大,同时又要保证一定事务读写性能的业务。
关于X-Engine引擎适用的业务场景请参见X-Engine最佳实践。
前提条件
实例为RDS MySQL 8.0高可用系列或基础系列。
购买RDS实例(X-Engine)
如果您需要使用X-Engine引擎,请在购买RDS实例时,基础资源页面选择实例类型为MySQL 8.0,然后在实例配置页面选择存储引擎为X-Engine(高压缩率)。其他参数说明请参见创建RDS MySQL实例。
RDS MySQL 5.5、5.6、5.7的用户如果需要使用X-Engine引擎,请迁移至RDS MySQL 8.0版本实例。详情请参见RDS实例间的数据迁移。
创建X-Engine表
如果创建实例时设置了默认引擎为X-Engine,则建表时默认引擎就是X-Engine。您可以通过如下命令查看默认引擎:
show variables like '%default_storage_engine%';
当默认引擎是X-Engine时,建表语句无需指定存储引擎。
表创建成功后,后续使用方法与InnoDB一样,数据会存储在X-Engine引擎。
实例上仍然可以创建InnoDB引擎的表,尤其是使用DTS迁移数据时,可能会出现迁移的表引擎仍然为InnoDB。解决方案请参见引擎转换方案二。
使用限制
与InnoDB引擎共存时的资源分配限制
使用X-Engine引擎时,95%的内存会提供给X-Engine引擎用做写入缓存和BlockCache以加速读写速度,留给InnoDB Buffer Pool的内存非常少,所以在X-Engine引擎的实例中尽量避免使用InnoDB引擎表存储太多数据,否则会因为缓存命中率低而导致性能大幅降低。建议使用RDS MySQL 8.0时,所有的表都使用相同的引擎(X-Engine或InnoDB),避免两种引擎混用。
引擎功能限制
X-Engine在引擎功能上有一些限制,其中部分功能尚在开发中。其他未列出的部分,默认其功能特性与InnoDB引擎相同。
分类
功能
X-Engine引擎
备注
SQL功能
外键
不支持
-
临时表
不支持
-
分区表(partition)
不支持(所有partition相关创建及增删改查操作均不支持)
-
Generated Column
不支持
-
Handler API
不支持
-
列属性
最大列长度
(longblob/longtext/json)
32MB
-
GIS地理数据类型
所有GIS相关数据类型均不支持(包含geometry、point、linestring、polygon、multipoint、multilinestring、multipolygon、geometrycollection)
-
索引
哈希索引
不支持
-
空间索引
不支持(所有fulltext索引相关的创建,使用均不支持)
-
事务
事务隔离级别
2个隔离级别:
读已提交(RC)
可重复读(RR)
-
最大事务
32MB
更大事务的支持在开发中
Savepoint
不支持
-
XA事务
不支持
功能开发中
锁
锁粒度
支持表级别锁
支持行级别锁
不支持GAP锁
-
Skip Locked
Lock Nowait
不支持
-
字符集支持
非索引列支持的字符格式
非索引列支持所有的字符集(校对规则)
-
索引列支持的字符格式
latin1(latin1_bin)
gbk(gbk_chinese_ci、gbk_bin)
utf8(utf8_general_ci、utf8_bin)
utf8mb4(utf8mb4_0900_ai_ci、utf8mb4_general_ci、utf8mb4_bin)
-
主从复制
Binlog格式
stmt/row/mixed
说明默认为row,采用stmt/mixed在特定并发场景可能存在数据安全性问题。
-
大事务功能限制
X-Engine目前不支持大事务。当一个事务修改的行数特别多时,X-Engine会使用commit in middle功能。例如用户在一个事务中修改的行数超过10000行,X-Engine会在内部把该事务提交,并且重新开启一个事务继续服务当前用户开启的事务。但是commit in middle并不能遵循严格意义上的ACID,您在使用过程中需要注意。以下举例说明:
用户开启一个事务插入大量数据,在插入的过程中,由于先提交了一部分数据,其它请求就可以访问到插入的数据。
用户开启一个事务修改大量数据,回滚的时候,已经执行了commit in middle的事务无法回滚。
drop table t1; create table t1(c1 int primary key , c2 int)ENGINE=xengine; begin; call insert_data(12000); //插入12000行数据,触发commit in middle,前10000行数据已经提交。 rollback;// 回滚只能把最后2000条数据回滚。 select count(*) from t1; // 这里仍然能够查询到10000条数据。 +----------+ | count(*) | +----------+ | 10000 | +----------+ 1 row in set (0.00 sec)
用户开启一个事务删除或者修改大量数据时,会遗漏掉本事务修改的行。
drop table t1; create table t1(c1 int primary key , c2 int)ENGINE=xengine; call insert_data(10000); begin; insert into t1 values(10001,10001), (10002,10002); delete from t1 where c1 >= 0;// delete操作触发commit in middle,导致delete操作没有读到本事务插入的行。 commit; select * from t1; +-------+-------+ | c1 | c2 | +-------+-------+ | 10001 | 10001 | | 10002 | 10002 | +-------+-------+ 2 rows in set (0.00 sec)
参数说明
在创建RDS MySQL实例时,可以选择X-Engine为默认存储引擎,也可以根据下表的参数说明调整参数模板以便适应自身业务。
类别 | 参数 | 说明 | 备注 |
性能 | xengine_arena_block_size | memtable向操作系统/jemalloc的外部内存管理系统申请新内存分配的单位。 | 启动后只读 |
xengine_batch_group_max_group_size | 事务流水线最大分组数。 | 启动后只读 | |
xengine_batch_group_max_leader_wait_time_us | 事务流水线最大等待时间。 | 启动后只读 | |
xengine_batch_group_slot_array_size | 事务流水线最大batch大小。 | 启动后只读 | |
内存 | xengine_block_cache_size | 读block缓存的大小。 | 不可修改 |
xengine_row_cache_size | 行缓存的大小。 | 不可修改 | |
xengine_write_buffer_size | 单Memtable的最大大小。 | 不可修改 | |
xengine_block_size | 磁盘上数据block大小。 | 初始化后只读 启动后只读 | |
xengine_db_write_buffer_size | 所有subtable的Active Memtable的总计大小限制。 | 不可修改 | |
xengine_db_total_write_buffer_size | 所有subtable的Active Memtable/Immutable memtable的总大小限制。 | 不可修改 | |
xengine_scan_add_blocks_limit | 每个请求在范围扫描时,可以加到BlockCache中的Block数目。 | 不可修改 | |
compaction | xengine_flush_delete_percent_trigger | 当Memtable中记录数超过此数目时,则xengine_flush_delete_record_trigger参数生效。 | 不可修改 |
锁 | xengine_max_row_locks | 单SQL请求中,最大可以锁定的行数。 | 不可修改 |
xengine_lock_wait_timeout | 锁等待超时时间。 | 不可修改 |
运行状态指标
下表为X-Engine的运行状态指标。
指标名 | 含义 |
xengine_rows_deleted | 删除行数。 |
xengine_rows_inserted | 写入行数。 |
xengine_rows_read | 读取行数。 |
xengine_rows_updated | 更新行数。 |
xengine_system_rows_deleted | 对引擎为X-Engine的系统表的删除次数。 |
xengine_system_rows_inserted | 对引擎为X-Engine的系统表的插入次数。 |
xengine_system_rows_read | 对引擎为X-Engine的系统表的读取次数。 |
xengine_system_rows_updated | 对引擎为X-Engine的系统表的更新次数。 |
xengine_block_cache_add | 向Block Cache添加次数。 |
xengine_block_cache_data_hit | 读数据Block命中Cache次数。 |
xengine_block_cache_data_miss | 读数据Block时Miss次数。 |
xengine_block_cache_filter_hit | Filter Block的命中次数。 |
xengine_block_cache_filter_miss | Filter Block的miss次数。 |
xengine_block_cache_hit | Block Cache的整体命中次数(data_hit + index_hit)。 |
xengine_block_cache_index_hit | 索引Block命中次数。 |
xengine_block_cache_index_miss | 索引Block miss次数。 |
xengine_block_cache_miss | Block Cache整体Miss次数(data_miss + index_miss)。 |
xengine_block_cachecompressed_miss | 压缩的Block Cache Miss次数。 |
xengine_bytes_read | 读物理磁盘的字节数。 |
xengine_bytes_written | 写入物理磁盘的字节数。 |
xengine_memtable_hit | Memtable命中次数。 |
xengine_memtable_miss | Memtable Miss次数。 |
xengine_number_block_not_compressed | 未压缩的Block数目。 |
xengine_number_keys_read | Key的读取次数。 |
xengine_number_keys_updated | Key的更新次数。 |
xengine_number_keys_written | Key的写入次数。 |
xengine_number_superversion_acquires | Superversion引用的申请次数统计。 |
xengine_number_superversion_cleanups | Superversion的清理次数。当一个Superversion无人再引用时则被清理。 |
xengine_number_superversion_releases | Superversion的引用释放次数,当一个Superversion的引用次数为0时则被清理。 |
xengine_snapshot_conflict_errors | 在RR隔离级别下,因为Snapshot版本冲突而报错的次数。 |
xengine_wal_bytes | Redo落盘字节数。 |
xengine_wal_group_syncs | Redo执行GroupCommit的次数。 |
xengine_wal_synced | Redo日志Sync的次数。 |
xengine_write_other | 在事务流水线中,作为Follower完成提交的次数。 |
xengine_write_self | 在事务流水线中,作为Leader完成提交的次数。 |
xengine_write_wal | 写Redo日志的次数。 |