黄东旭解析 TiDB 的核心优势
516
2024-02-25
TiDB 5.1 版本 GA 到目前已经有一年时间,在稳定性、易用性、性能提升等各个方面都做了很大改进和提升,例如:
支持列类型的在线变更 在 4.0 版本,某些列类型无法在线变更,例如业务需要修改 decimal 类型,虽然可以通过添加新列、将旧列数据更新到新列、重命名旧列、将新列重命名为旧列的变通方式完成,但是这种方式不仅适用场景有限而且耗时较长。而 5.1 版本开始支持 decimal 类型在线变更,大大提高了业务开发的灵活度。
在 LVS FULL NAT 模式下获取客户端 IP 公司 TiDB 集群前端负载均衡器使用的是 LVS,FULL NAT 模式, 这种模式存在的一个问题是:RealServer 无法获得用户 IP ,即在 TiDB 数据库中无法显示客户端真实 IP,显示的是 LVS 服务器上的一个 IP。很多时候,在排查 TiDB 问题时,需要获取客户端真实 IP,这给我们带来了一定困难。TiDB 5.1 引入了参数 enable-tcp4-only,开启此配置后,在 TiDB 数据库中可以显示客户端真实 IP,对排查问题有很大帮助。
Lock View 功能
自 v5.1 版本起,TiDB 支持 Lock View 功能。该功能在 information_schema 中内置了若干系统表,用于提供更多关于悲观锁的锁冲突和锁等待的信息
MPP 架构 TiDB 5.1 通过 TiFlash 节点引入了 MPP 架构,大幅加速聚合查询性能。
不可见索引 TiDB 5.1 引入不可见索引,可以帮助 DBA 提升调优 SQL 的效率及手段
以上只是众多特性中的一小部分内容,但是这些特性确实是业务和运维需要的,因此我们计划今年逐步将线上集群升级到 5.1 版本。在升级的过程中遇到一些问题和注意事项,这里记录一下。
升级步骤及注意事项可以参考 asktug 上的 【4.0 线上集群升级 5.0】SOP 手册,文末给出了链接,内容很详细。本节列一下我们从 4.0.9 升级到 5.1.4 新增的一些配置参数,仅供参考:
server_configs: tidb: enable-tcp4-only: true # LVS模式下查看客户端真实IP mem-quota-query: xxxxxx # 限制单条SQL最大使用的内存 oom-action: cancel # SQL超过最大内存取消执行 performance.feedback-probability: 0.0 # 显示设置为0 tikv-client.copr-cache.capacity-mb: 10000.0 # 缓存的总数据量大小 tikv: gc.enable-compaction-filter: true # GC新特性 rocksdb.rate-limiter-auto-tuned: true # 依据最近的负载量自动优化RocksDB的compaction rate limiter这里对一些参数做一下说明:
feedback-probability:建议将这个参数显示的配置到集群拓扑文件中,尤其是从低版本一路升级过来的集群,下文会提到关于这个参数遇到的一个小问题。
截止目前,我们已经将生产环境中的四套 TiDB 集群从 4.0 版本升级到了 5.1.4 版本(后续会逐步升级其它集群),本节主要回顾一下升级期间遇到一些问题和注意事项,需要大家注意。
这个问题比较严重,如果线上集群有哈希分区表,要从 4.0 版本升级到 5.1 版本,需要特别注意,否则可能造成故障,下面简要讲述下遇到的问题。
线上一套 4.0.9 的 TiDB 集群,升级时间是 14:00 ~ 14:35 ,升级完毕后,DBA 在 14:39 观察到集群 SQL 99 Duration 大幅升高,紧接着,业务在 14:42 反馈接口挂了。
DBA 开始分析基础监控,分析慢日志,发现慢日志里 TOP 3 的 SQL 全部来自于一张有 256 个哈希分区的表,而且这些 SQL 都使用了 force index ,所以理论上不存在走错索引的情况,SQL 类似如下
SELECT xx,xx,xx FROM club_bbs_all_256partion force index(idx_club_bbs_id_biz_id) WHERE club_bbs_id= 442 and club_delete_flag = 0 and is_publish = 1 order by biz_id desc limit 0,50\G SELECT xx,xx,xx FROM club_bbs_all_256partion force index(idx_club_bbs_id_post_date) WHERE club_bbs_id= 65 and club_delete_flag = 0 and is_publish = 1 order by club_topic_lastPostDate desc limit 20,20\G为了尽快恢复业务,DBA 和业务方沟通后,业务方将这个哈希表相关的 SQL 全部切回到了 ES ,之后 TiDB 集群恢复正常。 事后,我们复盘了一下问题,应该是 5.1.4 的哈希分区表的 Bug 导致的问题。
我们将出问题的那张哈希分区表和数据分别导入 4.0.9 和 5.1.4 进行测试,发现相同 SQL 在 5.1.4 版本上的性能和稳定性远不如 4.0.9 版本,同一个 SQL 在 5.1.4 上有时耗时 1 秒多,有时耗时 0.01 秒,交替频道出现,即使手动刚收集完统计信息,也会出现这种问题。
我们目前的解决办法是,将这个集群上的所有哈希分区表(幸好不多,只有几个)改造为普通表,之后再上线,没出过类似问题。
线上有一套集群是从 3.0 版本一路升级到 5.1.4 的(2021 年从 3.0 升级到 4.0 , 2022 年从 4.0 升级到 5.1.4),当天升级完毕后集群运行正常,第二天上午 7:00~10:00 点之间业务反馈接口抖动,同时观察到 TiDB 集群的 SQL 99 在相同时间段内也有抖动。但是分析 TiDB 集群,没发现什么异常信息。
最后检查到 feedback-probability 参数竟然是 0.05,虽然这个参数在 5.1 版本默认是关闭的,但是由于集群是一路从 3.0 升级过来的,所以如果不显示配置到集群拓扑文件中,这个配置还是 3.0 版本的 0.05 ,这里需要注意一下。官方文档建议关闭这个特性,即设置为 0 。
将 feedback-probability=0 配置到集群拓扑文件中,滚动重启 TiDB Server 节点后,再没出现过类似的抖动现象。
下面是集群出现问题时,TiDB SQL 99 监控和业务 TP 99 监控截图,可以看出抖动一致。
这里为什么要特意提一下 write stall 日志的事情,其实这个是一个注意事项,不是问题。
write stall 在 5.1 版本不仅日志文件名发生了变化,连日志所在目录也发生了变化,如果在 5.1 上遇到了 write stall 问题后还是按照 4.0 的分析步骤去分析,可能会被带偏方向,延长了排查问题的时间。
因为我自己就在生产环境中遇到过这个问题,线上一套集群从 4.0.9 升级到 5.1.4 后,过了一个月发生了 write stall 问题,从监控上已经得知了 write stall 的原因,当分析日志去辅助验证时,发现搜不到 Stalling 关键字了,更奇怪的是,LOG 日志最新的内容是升级当天的时间,然后就没日志了。不禁奇怪:为什么升级之后 LOG 这个日志文件就没日志了?是升级导致的问题吗?是某些日志参数默认值发生了变化导致的问题吗?还是其它原因?
以上都不是,可能是日志这块更规范化了,日志文件名和位置都发生了变化,具体如下:
TiDB 4.0 write stall 日志文件名和位置 /data3/tikv20173/data/raft/LOG TiDB 5.1 write stall 日志文件名和位置 /data3/tikv20173/data/rocksdb.info集群从 4.0.9 升级到 5.1.4 后,所有 TiCDC 节点频繁 panic ,无法启动,bug 详情请见https://github.com/pingcap/tiflow/issues/5266
解决办法:在升级之前,我们利用 drainer 搭建了一套应急集群,即 TiDB(5.1.4,业务集群) ---drainer---> TiDB(4.0.9,应急集群),由于 5.1.4 cdc 频繁 panic 导致无法使用,因此我们将 cdc 部署在了下游应急集群,作为应急使用。
升级后业务程序报错 Error updating database. Cause: java.sql.SQLException: client has multi-statement capability disabled. Run SET GLOBAL tidb_multi_statement_mode=ON after you understand the security risk 解决办法: 临时解决办法:在数据库端执行 SET GLOBAL tidb_multi_statement_mode=ON 长期解决办法:修改 JDBC 参数,添加 allowMultiQueries=true 配置
集群升级后,有一个业务SQL执行失败,现象如下,集群 sql mode 相同。
5.1.4 版本表现 user@xx.xx.xx.xx:4000 : test > select * from t1 as a where a.id=1; +----+ | id | +----+ | 1 | +----+ 1 row in set (0.00 sec) user@xx.xx.xx.xx:4000 : test > select * from t1 as a where .a.id=1; ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your TiDB version for the right syntax to use line 1 column 29 near ".a.id=1" 4.0.9 版本表现 user@xx.xx.xx.xx:4000 : test > select * from t1 as a where a.id=1; +----+ | id | +----+ | 1 | +----+ 1 row in set (0.00 sec) user@xx.xx.xx.xx:4000 : test > select * from t1 as a where .a.id=1; +----+ | id | +----+ | 1 | +----+ 1 row in set (0.00 sec).a.id=1 可能是业务写SQL时手误带入的.号,可能是集群升级后语法检查更严格,所以执行失败。
解决办法:将a.id前面的.去掉即可。
问题现象
TiDB 集群从 4.0.9 版本升级到 5.1.4 之后,业务上有一个 SQL(limit 100000)在 5.1.4 版本上无法执行出结果(给人的感觉就是 SQL 卡死了),但是在 4.0.9 上是可以正常执行出结果的。 在 5.1.4 上有以下几种现象: (1)max_execution_time 这个参数对这种 SQL 不生效,且超过 max_execution_time 时间后不会被杀掉,通过 tidb.log 看到有 kill 的动作([kill] [connID=6151100] [query=true]),但是没生效。 (2)这类 SQL 无法通过 kill tidb id 手动杀掉。 (3)通过 explain for connection 查看执行计划有 IndexHashJoin (4)这类 SQL 的执行计划在 4.0.9 和 5.1.4 相同
下面一个真实 SQL 示例,可以看到运行了 85113 秒还在运行中。
username@xx.xx.xx.xx:4000 : dbname > select * from information_schema.processlist where id=2765\G *************************** 1. row *************************** ID: 2765 USER: user HOST: xx.xx.xx.xx:26405 DB: dbname COMMAND: Query TIME: 85113 STATE: autocommit INFO: SELECT a.ext_json->$.topic_ids topic_ids,a.biz_id, a.biz_type, a.title, a.jump_url, a.author_id,a.author,a.recommend_time,e.uniq_brands_id,e.uniq_nlp_is_beauty,e.uniq_nlp_is_accident,e.uniq_brands_name,e.uniq_series_id,e.uniq_series_name,e.uniq_city_id,e.uniq_city_name,e.uniq_keywords_id,e.uniq_keywords_name,e.uniq_category_id,e.uniq_category_name,e.test_brands_id,e.test_brands_name,e.test_series_id,e.test_series_name,e.test_city_id,e.test_city_name,e.test_keywords_id,e.test_keywords_name,e.test_category_id,e.test_category_name FROM tb_user_pool a LEFT JOIN resource_pool_merge.uniq_nlp_tags e ON a.object_uid = e.object_uid WHERE a.recommend_used = 1 AND a.biz_type = 86 AND a.is_delete = 0 and e.object_uid is not null AND a.title is not null ORDER BY a.recommend_time DESC LIMIT 100000 DIGEST: 170b311194aee858def8776f9709c5e249a99636c07cfb338a5fdfbf7f598159 MEM: 973061709 DISK: 0 TxnStart: 06-06 16:00:42.826(433717888372179641)原因分析 可能是内部多个线程交互的时候,出现了死锁,IndexHashJoin 导致的 sql hang 住。
解决办法 (1)业务将 limit 100000 改为 limit 30000 或者更少 (2)利用 SPM 将 SQL 改为 inl_join,避免走 index hash join
新版本的新特性能很好地解决实际业务中的问题,但是版本升级本身存在一定的风险,因此我们和业务方要提前做好沟通、测试、回滚方案等,尽量避免升级操作影响业务或者将业务影响降到最低。
对于核心业务集群,建议通过 drainer 搭建好应急集群(版本是升级前的版本),一旦升级后出现不可预知的问题,必要时可以将业务切换到应急集群。
【参考文档】
https://asktug.com/t/topic/68547
https://pingcap.com/zh/blog/how-to-upgrade-tidb-happily
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。