前言
从4月份开始利用tidb改造了我们公司bi系统。这个过程中,我感觉到了tidb的强大。也打算记录一下整个改造过程。我打算从4个方面来记录这个改造过程。tidb架构选择,dm工具的使用——这两个部分还是tidb6.5.1,dm6.6版本上完成的,然后是7.1的新特性生成列和资源管控。
这是这个系列的第一篇——tidb架构选择篇
现状
公司经营游戏业务,有十几套mysql数据库,每一套对应一个游戏服,每个游戏服mysql结构是一样的。关键是年代久远,里面的表结构也大致在没有dba的情况下运行了4-5年。时间一长,问题就多,而且因为怕影响线上的业务和游戏体验,平时也基本不会停机维护。
最突出的问题就是数据写入没有问题,但查询非常慢,大表改造不停机又不可能,停机时间长了,老板也不接受。正好在2022年疫情封城的时候,我利用在家办公的时间了解过tidb。就建议老板,可以建立一个tidb集群,通过mysql binlog把写入流量整个接过来,相当于给现有的十几套mysql做个读写分离。凭我对tidb粗浅的认知,我认为只要数据进了tidb,就算处理的再慢,也不会影响线上的业务。而且通过binlog也能做到准实时的分析。老板对这个方案还是比较心动的,所以给了我一点预算,来做这个尝试。
我的目标
对我来说,平时做个报表,算个指标,改个数据,我都可以认为是正常需求。
最让人烦心的问题,在于某年某月的某一天,当业务人员找到你,指着一个指标说,这个数字是不是算错了。 这个问题就是最让人崩溃的,当他问出这个问题。你就要从指标算法找起,确认算法没错,在找到详细记录,一条一条的对过去。如果是算法的问题,多少和你还有点关系。不过大部分情况是业务人员就是难以相信某个指标就是这么好/这么差。然后你就要陪着他这么折腾一轮。
如果有一个计算指标足够快的库,这一切就会完全不同。我可以只存储详细记录,对应的指标和维度直接做成sql。当业务人员要看的时候算出来给他。当他觉得这个指标计算的有问题的时候,可以自己去掉维度和对应的聚合算法,直接找到详细记录。这样他有任何疑问都不用来找我了。我当然不指望新系统100%解决这类问题,但只要能解决90%也是极大的减少了我处理此类问题的精力。
实现这个目标的核心就是需要一个足够快的库,我希望tidb能做到这点,同时我选用了metabase做为bi的展示。metabase处理报表的方式非常接近写一个sql。是一个比较好的学习sql的拐棍。我也希望业务人员能通过metabase对sql有个感性认知,以至于最后大部分他们想查什么都可以尝试自己去点点鼠标尝试实现一下。我只要维护好基础数据就可以了。
现在回头来看,上述目标大部分应该是实现了。
tidb的架构选择
公司资源有限,小本经营。所以一开始我也就在腾讯云上申请了3台4核8g的云主机,总价每月也就1000出头一些,这个配置在文档内只配在测试环境做pd。
部署方式是典型的新手起步,每台1pd1tidb1tikv。tiflash监控这个时候还凑不出机器来装。监控更是和其他业务的测试环境挤一台。结果就是在导入3-4g大小的表的时候,集群就挂了。
翻了下监控,发现获取tso的时间巨长,应该是导入的时候,3台tikv把每个机器的cpu都跑满了,pd根本没有办法响应造成的。资源有限是一个现实的问题,如果我使用8核16g以上配置,成本上升的有点快。
所以我得到了第一个教训,小本经营的情况下,pd和tikv不能放一起。
好在加钱也不是完全没有空间。不过提高机器配置是没可能了,现有预算增加一下机器数量还是问题不大的。
仔细考虑了一下架构,要做到任何一台挂了,整个集群都可用。那tidb和pd起码2个,且不能和tikv放一起。tikv最好独占一台。接入写入流量主要考验整个集群的写入能力,满足最低3副本的基础上,我又多准备了一台tikv。这样就要再申请3台同配置的机器。1pd1tidb放两台,4个tikv。因为有2台tidb还需要一个粗浅的负载均衡,好在用haproxy不怎么占资源继续和监控放在一起——和其他业务的测试环境低负载机器挤一台。2个pd经人提醒有脑裂的风险,还需要一个pd节点,反正3个pd只有一个会用,这个新加入的pd只要解决脑裂的投票问题就行,所以继续和监控/haproxy挤一台。
此时的成本来到了每个月2000出头一些。
大体的架构经过导入大表时候的表现看是稳定了。偶尔会挂的tikv并不影响集群的稳定。
写入热点
如果说tidb和mysql有什么显著的区别,我认为写入热点应该是排在第一的。
在我这个机器配置下,除非mysql的表上的数据小于100w,照搬mysql的建表语句还算可以接受。
大于这个量,如果不做表结构的修改,直接导入肯定能在流量可视化里面看到写入字节量这个图里面有一条明亮的斜线。这就是写入热点。
对于写入热点问题,文档里面给出方案也无外乎两种:
1,聚簇索引表+anto_random 2,非聚簇索引表+SHARD_ROW_ID_BITS+PRE_SPLIT_REGIONS
简单来说,非聚簇索引表不管你的主键如何设置都会生成一个_tidb_rowid来做这个表的主键。
所以查询和写入都多一次回表。而聚簇索引表就没有这一次回表。
从原理上来说,在某些场景下(在dm篇细说),确实聚簇索引表是更好的选择,但是记得我开头写的目标吗?我的目标是当指标计算有问题的时候,业务人员自己能找到详细记录,如果这个详细记录使用了anto_random和原本在游戏服数据库上的记录对不上。那我不是给自己挖坑么。在这个问题上,我宁可为难一下tidb也不要为难我自己。
所以对表结构的改造,我全部采用了非聚簇索引表+SHARD_ROW_ID_BITS+PRE_SPLIT_REGIONS的方案。 上游继续用它的anto_increment。
只要有点数据规模的(10w-100w条)就是SHARD_ROW_ID_BITS=2 PRE_SPLIT_REGIONS=2,预分裂region数4,最高8。
超过1000w的直接SHARD_ROW_ID_BITS=5 PRE_SPLIT_REGIONS=5,预分裂region数32,最高32.
经过我的实际测试,在有4tikv的情况下,如果你想要负载均衡,你预分裂的数量要比4大一些,才容易均衡。
在对于某个大于1000w的表设置为SHARD_ROW_ID_BITS=2 PRE_SPLIT_REGIONS=2的进行大表导入测试的时候,预分裂region4,tikv实例也是4,我以为会是均衡的。实际导入大表观察4个tikv,其中某一个tikv cpu一直只有10-20%的负载,其他3台tikv都在380%左右,cpu基本跑满。
所以之后对这种表都宁可预分裂的大一些。防止写入负载不平衡。
另外假如你做好了表结构不是立刻进行导入,还需要调整表属性。https://docs.pingcap.com/zh/tidb/stable/table-attributes#%E6%96%B0%E5%BB%BA%E8%A1%A8%E6%88%96%E5%88%86%E5%8C%BA%E7%9A%84%E5%86%99%E5%85%A5%E7%83%AD%E7%82%B9%E9%97%AE%E9%A2%98
防止预分裂的region被提前合并掉。当然大批量的导入完成了就可以考虑去掉了。
这就够了吗?显然不够,写入热点是一个需要时时刻刻考虑的问题。
create table t_new as select * from t;
你要考虑t有多少数据,表结构是什么样的,这样复制/备份是否会有写入热点。
insert into t1 select * from t;
你还是要考虑t有多少数据,t1的表结构是否改造过,会不会有写入热点。
总之,写入热点问题,是一个你需要时刻注意的问题。
修改事务隔离级别
https://docs.pingcap.com/zh/tidb/stable/system-variables#transaction_isolation
tidb的默认事务隔离级别是REPEATABLE-READ.这个事物隔离级别是比READ-COMMITTED要高的。显而易见的问题是,代价肯定也比READ-COMMITTED要大。关键还不讨好,大部分研发人员还是习惯READ-COMMITTED。所以显得没有必要,改回READ-COMMITTED,皆大欢喜。
监控告警
这是tidb篇的最后一个问题。当你安装好监控后,并不会收到任何信息。打开alertmanager.yml你会看到里面有如下配置:
route:
# A default receiver
receiver: "blackhole"
receivers:
# This doesn't alert anything, please configure your own receiver
name: "blackhole"
消息都发进了黑洞,你当然收不到任何东西。不开大就等于空大。花了资源部署了就必须有用。
公司的监控信息是往企业微信群里发的。那个时候我翻了社区还没有webhook往企业微信群里发的案例(现在有了,感谢社区 https://tidb.net/blog/199877a0)
我当时采用的方式比较原始,就是alertmanager.yml+微信告警的模板文件tmpl。本来写的一大段,现在一看还不如上面这个好。就不献丑了。推荐用上面这个。
总之不管用什么方式,告警还是要弄好,有些重复/固定触发的(我这个4核8g的配置,tikv内存超过80%的告警基本一直有,就算tikv挂了,不要2个小时也必出这个告警)可以设置一个长期的静默时间过滤掉不看,但告警不能没有。这是个原则问题。