本文介绍我和物化视图的恩怨情仇,以及我是如何用物化视图每年省下100W的。
一台32核的oracle服务器是怎么被拖垮的
问题背景:
某公司的业务数据库中有8张业务大表(那些数据量不大的表以及忽略),8张大表的设计非常符合数据库的设计范式,比如:table1 <= table2 ; table2 <= table3; table2 <= table4; table2 <= table5; table1 <= table6…
8张大表每秒的TPS之和约为100,如果统计这8张表一天的cdc(change data capture),大约是每日新增8,640,000条CDC变更记录。
经过数年的运行,这8张大表目前的累计数据量均到达千万级甚至亿级。
业务中经常需要对这8张大表进行关联查询,为了提升查询性能,机智的DBA将8张大表中的3张大表通过oracle的物化视图功能进行了关联(为什么不是8张,因为光是这3张大表的物化视图开销已经占了oracle服务器的一大块CPU以及IO资源,不能再多了)。
随着时间的推移,oracle数据库越来越累(很大程度是被这个物化视图拖慢的),而业务对查询性能还是嗷嗷待哺。
阿里云blink水土不服
时间来到2019年,“上云就上阿里云”的呼声越来越高,尤其是看到杭州城市大脑的成功案例之后,上头领导决定上面这8巨头(8张业务大表)也要上云了,上云的具体原因咱也不知道,反正就是要上。
于是请了所谓的阿里专家来评估上云方案,阿里专家稍作思索便推出了一系列阿里的王牌产品,什么rds-mysql,rds-pg,ads,blink,datahub等等。最后终于讨论到该如何处置这个8巨头了,阿里专家眉头一皱,提出了一套通过强大的blink流处理引擎替代原来的oracle物化视图的方案。毕竟城市大脑和双十一大屏都在用,稳妥的。
完整的方案大概是:先通过ETL工具把数据从云下的oracle抽到阿里云的rds-mysql,通过mysql的binlog产生CDC(change data capture),再把CDC数据流抽到datahub,然后blink再进行临门一脚(只需要写 关联sql即可,一行代码都不需要写)。
看起来很美的方案,后面却花了半年时间踩坑(吐槽一下,阿里云的东西真难用,私以为根本原因还是太黑盒了,文档太垃圾,举个例子不妨对比下ADS的文档和mysql或者oracle的文档;另一方面遇到问题只能提提工单,专家们的问题解决效率低得一批)。
半年过去blink终于吐出数据了,还没高兴几个小时,突然blink一片飘红资源不够用了,马上提工单请阿里专家,专家一日复一日的又是调后台参数,又是优化这优化那,最后还是巧妇难为无米之炊–加计算资源,200CU起。这时候才发现这个blink真是贵的一批啊,一个CU一个月两三百块钱,了不得这一年光这玩意就50W了。==
只要blink能好好干活,咬咬牙这钱该掏还得掏。blink终于开始稳定吐数据了,我高兴的写了个数据校验的程序(https://github.com/DLX4/diff-mark)。一看结果,心凉了半截,又是丢数据,又是数据错误。马上又提工单请阿里专家攻关,想不到大半个月过去了依旧垃圾。
城市大脑和双十一的神话咋到我这就不灵了呢?
手写物化视图
阿里云萎了之后,我又把我半年以前被搁置的方案拿出来琢磨(就是这个方案:https://dlx4.github.io/2019/12/31/big-wide-table/)。以前大家都不知道业务具体的TPS到底是多少,毛估估觉得是不可触碰的,只是凭经验考虑觉得我这方案不太可行,毕竟连传说中的blink也有点肾虚乏力的。
不过这时候我可以看到CDC的增长数据了,于是我在草稿本上算出了8,640,000(这是一天的TPS),每秒100TPS要是撑不住我就再用业务逻辑sharding然后并行处理。
于是花了一天半时间手写了物化视图实时刷新数据的代码,测了下TPS大概可以做到最多600(得益于网络延迟少以及所有操作均是基于索引)。
接下来就是保证业务逻辑一致性了,我花一天半手写的程序大概只有95的数据是正确的(因为如果上层应用代码质量一般的话,CDC的数据会比较脏,而且还遇到了CDC数据迟到等问题)。于是开始一手开发数据校验程序,一手开发手写物化视图程序,真的是左右互搏。左右互搏了一个星期之后准确性终于收敛到99.999..%了。
启示1
复制自己的话:
从95%左右开始 程序逻辑我就不能主动考虑的到了 全是靠大量的数据和时间磨出来的准确性,后面还是靠发现问题解决问题进一步提升准确性。
相比于blink通用的流计算引擎代码,我们的代码是从头手写的并且只面向这次的宽表逻辑,因此不通用,下次要是有类似的开发任务还是要改代码然后打磨准确率。
但是我们的好处是可以自由访问原生的源表,因此可以非常容易的实现redo的流处理逻辑,从而保证一致性。而blink只能从流和窗口缓存或者维表中读数据,实现肯定复杂的多。
效率上目前看来比blink高效很多,只用了4个线程就能达到两张宽表分别600TPS的写入(比xxx目前的数据量要高出20倍);但是blink可以用集群CU去分布式并行处理,而我们只能单机多线程处理,这里还是blink更牛,在数据量超过100倍xxx数据的时候可能就要用blink或者其它大数据框架了。
启示2
之前了解到现在一部分人设计数据库的时候都喜欢加冗余字段,喜欢逆范式而行把数据库设计的比较扁平。有段时间我也是这么想的。但是这样做的不好的地方在于:冗余数据的维护成本(保证一致性),甚至会把业务代码搞很乱。这种做法的本质逻辑还是压缩多表关联的成本,代价一点没有减少相当于时时刻刻要维护这个“宽表”。
如果手写物化视图能够:
1、近乎实时(上面我的代码可以保证2秒内一致性,当然不考虑数据迟到);
2、解耦(手写物化视图的代码可以单独部署运行)
3、开销不大
那么这岂不是鱼与熊掌可以兼得了,既有范式带来的优雅,同时又能保证性能。真是666.