“让技术被看见 | OceanBase 布道师计划”由 OceanBase 主办,CSDN 协办,面向广大开发者的年度征文活动。全年 4 轮,以季度为周期进行优秀文章评比,每年 1 届,以年为单位进行最佳布道师评选。
目前,首轮技术征文获奖文章已评选出炉,本篇内容为「OceanBase 布道师计划」优秀文章之一,作者 YoKing Ma,从事于一家总部位于宁波,业界领先的新能源上市公司,公司业务涵盖光伏新能源产品的开发、制造及销售。
评委有话说
屠敏(CSDN 资讯主编、《新程序员》特约专栏记者):文章分享在传统监控数据存储中引入 OceanBase 的实践过程,清晰地阐述了现有架构的痛点以及 OceanBase 的优势。通过对比 MySQL 架构,作者展示了 OceanBase 在性能、可扩展性和高可用性方面的实践。整体内容实用且具有一定深度,为监控数据存储领域的技术探索提供了一些思路与启发。
封仲淹(OceanBase 开源生态总监、OceanBase 开源社区负责人):文章从一个非常具体的场景出发,整体上给用户一个新的解决方案 Zabbix + OceanBase 的方案,给 Zabbix 用户和 OceanBase 用户一个新的思路,整个文章中,细节满满,非常详实;在文章中,详细的描述了之前 Zabbix + MySQL 所遇到各种细节问题,并介绍如何进行选型,对比候选系统,最终使用 OceanBase 获得收益。
老鱼(资深 IT 媒体人、《老鱼笔记》主理人):文章介绍了公司选用Zabbix监控系统的背景、遇到的问题、优化思考及最终选择OceanBase的过程,通过实际案例展示了OceanBase在处理大规模监控数据时的性能和成本效益,为同类企业提供了迁移经验。
章芋文(墨天轮社区负责人):本文深入探讨了OceanBase在Zabbix监控数据存储中的应用,通过宁波新能源上市公司的实际案例,展示了从MySQL迁移到OceanBase的全过程及其带来的显著效益。文章条理清晰、逻辑性强,从监控架构介绍到MySQL的局限性,再到OceanBase的优势分析和部署实践,逐步揭示了OceanBase的高效性和实用性。具体性能提升和空间节约的数据支持,进一步证明了其在企业级应用中的实用价值。总体而言,这篇文章技术含量高,实践指导性强,对数据库专业人士和企业决策者具有很高的参考价值。
作为产值百亿的企业,监控系统是重要的IT管理工具之一,对保障企业业务连续性、预告风险有重要意义。2022年,公司选用Zabbix为企业监控系统,对公司分布在国内外的服务器、操作系统、中间件、数据库、网络设备等进行指标监控;对集团业务系统设置监控预警,确保集团所有系统异常时准确告警;对IT设施的巡检、事件的回溯提供指标数据支撑,便于IT管理人员可以快速获取系统中各个组件的历史数据。
监控业务架构介绍
之所以选择Zabbix是因为其开源,且经过多年发展,不仅架构稳定还具备“监控万物”的能力,适合我们这种以传统架构为主,云原生架构比例很低的企业。公司内部相关IT人员也有Zabbix使用经验,上手门槛较低。
彼时,笔者刚加入公司,对刚上线的Zabbix监控系统做持续且深度的优化和改造,不断提升监控系统的及时性、准确性。由于Zabbix底层数据库使用MySQL 8.0,被MySQL的架构限制,因此,很快就出现了问题。
基于MySQL的监控业务架构痛点
第一个问题,架构高可用瓶颈,无论选择哪种架构,都不尽人意。
主从架构的问题:
双主架构的问题:
MGR架构的问题:
(1)非读写方式,与单点的性能无差异不推荐。主节点故障后,需要停机切换,还需要校验主从节点的数据差异,所以不推荐。
(2)读写分离方式有2种改造方式,一是改造DAL层代码,这种方式影响后续版本功能的迭代,不推荐;二是引入如 ProxySQL的中间件,但增加了一层组件,在性能和可靠性上有所降低。
(1)单写是我们目前采用的方式,节点上套用一层keepalived作为虚拟地址,方便切换。
(2)双写的话需要控制写入行的ID,避免主键冲突和数据冗余。需要改造,不推荐。
(1)一致性强,但需要配合如ProxySQL之类的中间件实现读写分离。在实际测试中,MGR容易产生雪崩效应,即一个节点掉出后,可能导致整个集群崩溃。
所有采用复制方式的架构最大的问题点在于,Zabbix的写入量很大,binlog不能保留太久(非常占用磁盘空间),如果复制关系断开太久会导致主从节点之间无法找到同步位点,无法重新同步上。
第二个问题,读写冲突。Zabbix的写入量很大,在业务高峰时段,运维人员和业务人员查询监控数据、history数据向trends数据转换、告警比较等,很容易产生读写冲突(乐观锁)。但Zabbix还有一个管家服务,会定期清理过期的监控数据,这容易造成悲观锁,使数据库性能急剧下降。在数据量不断增大的同时,这个冲突会越来越明显。
第三个问题,容量问题。尽管对监控项的数量、保留时间做了大量的改造,但仍有大量的数据需要保存下来。运行1年多,Zabbix的数据库已经超过1TB,最大单表数据量超7亿。数据本身的容量只是问题中的其一,其二是InnoDB的binlog。
基于监控架构痛点,我们需要结合业务情况进行优化,下面是我们对优化的思考。
优化MySQL难以解决根本问题
在众多优化案例里,笔者挑选了一个典型的数据优化案例来分享。
在制作Zabbix监控模板时,其中Linux操作系统监控模板的监控项就多达100个,面对公司2000+生产级别服务器,监控项规模达到了20w个,假设每隔5分钟对所有的监控项收集一次数据,那么,每小时数据库库中将有20w*(60/5)=240w 笔数据要写入history表。
5分钟采集一次是一种理想情况,因为采集间隔变大后,数据的精度会降低。对于一些流量数据、CPU、内存、I/O等使用率数据,用户往往要求以较高的精度采集,采集间隔可能是在1分钟左右,这样的代价是产生了更多的监控数据。
同时考虑到 history 到 trends 转换,每小时从hisoty 和 history_unit 表中取出完整1小时的监控值进行运算后(min、avg、max),分别 insert 到 trends 和 trends_unit 表中。
这个过程中,查询到的结果集大、运算量大,需要大量的缓存,往往引起MySQL的临时表或临时表文件创建过快、磁盘I/O过大、占用SWAP、引发大事务等问题。
随着数据量的增大,以及上文提到的事务悲观锁冲突,导致在清理历史数据时,往往会清理任务失败,进而历史数据越积越多。同时,锁表的问题导致在环境中无法使用dump方式进行备份,只能使用物理备份。但在使用物理备份时,由于清理历史数据的过程中使用delete方式,造成主要业务表中的空间未得到正常释放,产生碎片,在备份前需要进行碎片整理,使得备份业务推进起来非常艰巨。
大批量的insert、delete操作使服务器的binlog变得庞大,导致存储压力很大。调小后,如果主从一断,主库上的binlog位点很快就会循环覆盖,导致从节点要重新恢复才能加入到集群。
对于上述问题,结合Zabbix数据库中的数据表,我们就需要通过优化以下数据表来解决问题。
其中,以 history 开头的表为存储历史数据,trends开头的是趋势数据。历史和趋势是在Zabbix中存储数据的两种方法。
History,历史保存着每一个item的数据。即从客户端收集过来的原始数据,这部分表的表结构都差不多,唯一的不同是保存的数据类型。如果一个监控项(item)一分钟采集1次,那每天就有24*60*60=86400笔数据。
Trends,是每小时监控的数据聚合后的结果,保存一小时内某个item的平均值、最大值和最小值,可以理解为是history表的压缩数据,因此减少了对资源的需求。
(1)如果是数值类型,表中字段如下:itemid bigint(20)、clock int(11)、value bigint(20)、ns int(11),大概一笔数据是8+4+8+4=24 B,一天有24*86400≈2 MB;
(2)如果是history_str 或者 history_text 两个表,其中的数据字段变成了value varchar(255) COLLATE utf8mb4_bin 和 value text COLLATE utf8mb4_bin ,varchar(255) utf8mb4 最长是 255*4=1020 B,而text 字段最大可以到65535 B ,我们考虑极端情况,一个字符型或文本型的 item ,按1分钟采集1次,分别对应产生的数据量为(8+4+1020+4)*86400≈85 MB 或 (8+4+65535+4)*86400≈5 GB ;
(3)历史数据的大小取决于监控项(item)条目数量、保留时长、监控项(item)值类型、监控项(item)的采集间隔等条件。
(1)trends 仅针对数值类型的 history 表,而 history_str 、history_log 和 history_text 是没有趋势表的;
(2)趋势表是由历史表通过housekeeper(管家服务,类似与一个定时任务)转换而来,转换过程必须消耗数据库的性能。
从索引开始
history表中存在2个时间字段,一个是clock,另外一个是ns,接收item值时的时间值存放在两个字段内,大于1秒的部分存放找clock字段单位是秒(s),小于一秒的部分存放在ns字段单位是纳秒(ns)。
两个字段相加的值才是接收item值时的时间值,一般不用关心小于1秒的部分。但是,在Zabbix自己做统计时很多查询中都用到了这两个字段,而这些表中,并没有在ns上面做索引,导致了全表扫描,所以我们将history表进行改造:
CREATE TABLE `history_old` (
`itemid` bigint(20) unsigned NOT NULL,
`clock` int(11) NOT NULL DEFAULT '0',
`value` double NOT NULL DEFAULT '0',
`ns` int(11) NOT NULL DEFAULT '0',
KEY `history_1` (`itemid`, `clock`) BLOCK_SIZE 16384 LOCAL
) DEFAULT CHARSET = utf8mb4
CREATE TABLE `history` (
`itemid` bigint(20) unsigned NOT NULL,
`clock` int(11) NOT NULL DEFAULT '0',
`value` double NOT NULL DEFAULT '0',
`ns` int(11) NOT NULL DEFAULT '0',
PRIMARY KEY (`itemid`, `clock`, `ns`)
) DEFAULT CHARSET = utf8mb4
其余history表的改造参照上面的方法
表分区
针对history系列表和trends系列表进行分区,定期create 分区和drop 分区。在做分区管理时,遇到三个问题。
第一,因为监控数据表的数据量太大,直接在源表上操作风险很大,执行效率也会很低。所以采用了创建新表,然后将原表中的数据insert /*+ ENABLE_PARALLEL_DML PARALLEL(2) */ …… select …… 的方式处理(这里用到了OceanBase DML的并行,具体可以参考https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000001050810),但发现部分数据量少的表还能够导数成功,大表、业务繁忙的表根本无法执行。
第二,如果我们使用dump方式去备份还原表,中间停机时间要很久。
第三,使用 DataX做数据同步的话,什么时候追平数据,如果中途停止,找最后位点的难度很大。
MySQL参数优化
在Zabbix中使用频度最高的就是将最新的数据写入数据库,按一定的时间间隔,将历史数据(history)转换趋势数据(trends),删除过期的历史数据,以及IT运维人员查询监控数据、报表(grafana)等操作。查询(排序、汇总、计算)、增删(大事务)会极大地消耗MySQL数据库的性能,使业务的处理时间变长。最简单的优化方案就是优化MySQL的innodb buffer pool、query_cache_size、tmp_table_size、innodb_log_buffer_size、 sort_buffer_size、read_buffer_size、join_buffer_size、binlog_cache_size的大小,尽可能将数据留在内存中,加快数据的处理速度。
但是无论如何优化buffer,也不能无限制的增大,当达到物理内存的上限时,就需要去扩容内存。同时,大量的大事务会过度消耗磁盘I/O(当脏页达到一定量的时候就会落盘,落盘就会产生I/O),加剧数据库的压力。底层物理设备的扩容会涉及停机、迁移等中断服务的事件,也是额外增加成本。
可见,在MySQL及操作系统的调优和扩容硬件的方法始终会有尽头或者瓶颈,不是最优解,我们需要寻找新的出路。
寻找新的出路
对于新的数据存储方案,我们希望除了能够解决现有架构瓶颈和业务痛点外,还需要具备三个条件:
1. 必须兼容MySQL的语法、函数与表达式、数据类型、表分区、字符集、字符序。
2. 具备HTAP能力,能够在基于关系型数据结构在数据引擎层面处理好TP和AP的关系。
3. 在不依托于其他技术手段的情况下具备高可用、多活能力。
由于Zabbix server 支持MySQL、PostgreSQL,但团队中没有人熟练驾驭PostgreSQL,同时,在Zabbix的 MySQL 数据库上已经开发了比较多的应用、报表,如果贸然将数据库从MySQL切换成PostgreSQL,需要对之前的应用、报表做再开发,因此,暂时不考虑PostgreSQL,于是将选型的范围放在兼容 MySQL 模式的数据库。
上文提到我们同时在使用InnoDB引擎,MySQL的TokuDB引擎作为InnoDB引擎的优化升级版本,就成为了我们选型数据存储方案中的备选。
首选还是考虑目前热度较高的新兴数据库,比如TiDB、华为GaussDB和openGauss、OceanBase、达梦数据库。
TiDB不支持MySQL的存储过程、外键,首先排除。
openGauss基于PostgreSQL,与PostgreSQL数据库一样,作为第二梯队方案。
华为GaussDB需要付费购买,暂时不考虑。
达梦数据库需要付费购买,暂时不考虑。
OceanBase兼容MySQL,支持分布式,而且开源,可以进行下一步调研。
在兼容性的综合考量下,将TokuDB引擎、OceanBase作为优选方案。
综合考虑下,由于TokuDB读能力不满足预期,OceanBase支持HTAP、多活高可用,以及社区活跃,有非常多的参考资料,容易上手。因此,我们最终决定使用OceanBase。
上线OceanBase
我们按照官方文档执行部署,过程中遇到了一些小问题,通过查询官方文档、咨询社区技术人员等方式逐一解决(后续我会把部署过程分享到博客中,大家可以拍砖、借鉴)。
总的来说,OceanBase的上线流程较为顺利,从 MyySQL 迁移到 OceanBase非常容易。因为我们用的是OceanBase 社区版,所以,在迁移前无法使用迁移评估(OceanBase Migration Assessment,OMA)来对迁移过程进行评估,只能依靠经验来判断,在社区的官方人员和社区用户群朋友们的帮助下,我们在迁移前做了如下检查,供大家参考。
字符集检查。因为OceanBase没有完整支持MySQL的字符集和排序,所以,需要在迁移前做好评估。
OceanBase中没有event,原库中有event时,需要通过别的方法实现,后文列举了案例。
OceanBase中对大小写不敏感,有些MySQL库可能对大小写敏感,所以要注意原库中lower_case_table_names的配置。
如果需要做反向同步,在原库中提前建立好相应的账号、授权,并把omstxndb库建立好。
如果主外键约束的话,需要提前关闭主外键约束检查SET FOREIGN_KEY_CHECKS=0;
相关各个节点的解释参见官方文档(https://www.oceanbase.com/docs/community-oms-cn-1000000000958779)。此外,上文中提到的在Zabbix的history相关表,trends相关表需要实现表分区。分区管理需要定时任务,否则管理员定期维护分区的工作量很大。在MySQL中,我们可以通过Event+存储过程的方式来实现自动化。而由于OceanBase中没有event,这似乎又要碰壁了。俗话说:“当门关上的时候,会给你开一扇窗”,因此,我们可以使用OceanBase 的ODC(开发者中心。OceanBase Developer Center)来实现,这是一个开源的企业级数据库协同开发平台。里面集成了“分区计划”的模块,可以将其看作MySQL中的Event+存储过程方案的Plus版本。具体可以看我之前的博客:https://open.oceanbase.com/blog/12521093139
新库新征程
在写本文时,我们的Zabbix监控系统已经在OceanBase中运行了半年,相比之前使用MySQL时,从资源配置上来讲,在获取相同性能的情况下,可以大幅降低硬件平台的投入。
最初,由于OceanBase兼容MySQL,公司的开发人员和系统管理人员对于数据迁移并没有表示反对,在迁移过程中,OceanBase的高可靠、HTAP等能力使笔者在与业务系统运维部门沟通迁移计划时都比较顺利,迁移后带来的性能提升和80%的空间节约,也让业务部门非常满意。
在性能提升方面,最直观的感受是之前在查询周期较长的历史数据(几周或几个月)时,通常需要好几秒(至少4秒)时间才能将数据渲染出来,现在运行在OceanBase上之后,基本上点击完后就可以立即加载出统计图;另外一个感受就是,以前zabbix有各种各样的性能告警,频度也比较高,自从迁移到OceanBase上之后,此类告警明显减少。
总而言之,OceanBase是一个符合我们预期的数据库平台,目前,我们也在不断探索和实践OceanBase的新功能。以下,我将结合公司业务场景与OceanBase的功能进行简单总结。
支持并行,对于大量数据的操作,打开并行功能,可以大幅提高处理的效率。
对于资源的热更新,依托于OCP平台,可以对于数据库的资源(CPU、内存等)、zone、参数进行热更新,减少停机。
压缩率高,我们在导入Zabbix数据库时,在MySQL上看到的库的大小是1.2TB,导入OceanBase后,数据库的大小只有260GB左右,数据量缩小了80%,,极大地节省了存储空间。
与生俱来的伸缩性和分布式能力,可以支持在线横向(扩展zone)、纵向(扩展分片)扩容,所有的数据同步都交由后台自动完成,基本不需要人工参与。不论是横向还是纵向都提供了数据的冗余能力。原先我们还尝试过使用MySQL的MGR,虽然保障了一致性,但运维过程非常艰辛,一旦有节点挂掉很有可能把整个集群打穿。
支持慢查询单独队列,如果遇到慢查询,OceanBase会将慢查询放在一个单独的队列里面慢慢执行,不影响短平快的查询,不阻塞。
此外,OceanBase丰富的生态工具也为我们带来了更加自动化、更加便捷的运维管理能力。
首先,OCP 为数据库的管理提供了很多实用的功能:
云原生、多租户:可以将数据库在一个平台统一管理,简化数据库的创建、运维浑然一体。使用租户模式,实现租户与租户之间资源隔离。
SQL诊断:集成SQL诊断功能,便捷、快捷的观测TopSQL、SlowSQL、并行SQL。可以通过可视化的手段,观测SQL的执行情况、快速诊断。
备份:原生支持物理备份和日志备份功能。
其次,OMS支持 OceanBase-CE、MySQL、PostgreSQL、TiDB、Kafka 和 RocketMQ 等多种类型的数据源与 OceanBase 社区版进行实时数据传输,以及 OceanBase 社区版 MySQL 租户间的数据迁移。
通过自动化、流程化的方案,轻松对数据进行迁移,简化迁移流程。
在一个流程中支持结构同步、数据同步、数据增量同步、数据反向同步,减少运维人员的运维工作。
支持通过匹配规则对部分表进行同步、对表中的数据进行同步。
最后,ODC作为开发者中心,提供了许多便捷的功能,比如:
集成了SQL开发的IDE功能,同时在开发过程中可以对SQL进行审核,对于高风险的操作进行二次确认。
支持工作流,可以实现数据源访问权限的审批,增加协同性能。
支持与企业AD做集成身份验证,方面管理账户,增强安全性。同时也可以当做数据库访问管理的平台(类似堡垒机),关键是免费!
支持对接OceanBase MYSQL模式,同时还支持了MySQL、Oracle的接入,是企业数据库IDE薅羊毛的好工具。
支持定时任务:
(1)SQL 计划:定期执行一段SQL,类似于event功能。
(2)分区计划:原生支持分区创建、删除的功能,非常好用,可以参照我的博客《zabbix 大表在OceanBase中实现表分区管理》。
(3)数据归档:对一些历史数据通过一定的规则进行归档(从一个表(库)中复制到另外一个表(库))当中。
(4)数据清理:按照规则,定时清理表(库)中的数据。
(5)对与所有的执行作业可以查看执行是否成功,方便运维。
(6)所有功能开箱即用,省时省力。
憧憬未来
对于OceanBase的这些特性,结合我们实际的业务,未来会将更多的库迁移到OceanBase上面来。目前正在进行的有生产设备数据采集系统(下称:数采系统)、报表系统的迁移。
数采系统的需求也是类似于Zabbix,特点是:
数据量大。部分数据都以秒级从生产设备中采集数据,并发量大,数据量大,导致整个库里的数据会很大。
数据时序性。部分表被设计成了横表,横表中存在时序字段,在查询时需要将横表转换为纵表,查询过程复杂关联多,这里我们使用了窗口函数来解决时序内采集结果的对比分析,后面可以升级到OceanBase新版,采用列存方式实现。
定期归档、清理:这个功能可以结合ODC的数据归档和数据清理功能。在清理过程中结合并行方式,加快处理的能力。
表分区。对大表进行分区管控。
报表系统的特点是:
典型要求HTAP,借助于OceanBase支持慢查询队列,可以有效的保障大事务、大查询最大程度不干涉短平快事务的执行。
当然,一切美好的背后,仍然是有存在不足的地方,执行计划不仅难读,还抖动、恶化,导致SQL在执行时候不稳定,而且系统日志理解困难,另外对于中文的支持还是有提升空间,我们在测试OceanBasedumper时,遇到了中文表名备份失败的问题(目前社区还在分析,临时方案是回退到了一个旧版本来解决)。
结语
OceanBase的功能非常强大是事实,每一个事务都在不断进步。从我们试用到使用OceanBase的过程中,有“坑”也有惊喜,遇到问题,先看手册,自己思考。如果自己想不明白可以再社区的问答板块和用户答疑群寻求帮助,社区的老师会及时答复(相较于其他开源社区,OceanBase的及时性和准确性要好很多)。
OceanBase还在不断发展,对于4.3版本中的列存、物化视图等功能还等着我们探索,道阻且长,行则将至。