从mysql到原生分布式,三维家 all-c7电子娱乐
三维家公司,自创立以来已稳健发展11载,专注于云建模、云渲染、三维矢量ai三大自研核心引擎的研发与应用。三维家致力于为制造业提供新一代“云化”、“ai化”、“设计/展示/加工一体化”的云工业软件c7电子娱乐的解决方案,助力企业实现数字化转型与升级。在过去的十年间,三维家凭借卓越的技术实力和服务品质,赢得了广泛认可,在其所专注的领域内已跻身前列,成为业界的佼佼者。
三维家致力于解决前后端一体化的工业难题,以云工业软件助力产业升级。在前端,用户可以通过三维家的网页界面轻松进行设计操作;在后端,三维家通过精心设计的场景,确保这些设计与工厂的机器设备紧密相连,实现无缝对接。数据直通生产线,板材裁剪一气呵成,最终将产品寄送给客户进行安装。通过工业软件,用户可以轻松将设计转化为现实。
业务背景简介:基于mysql分库分表的数据库架构
对于这样一家以前沿技术与数字化能力为基石的现代化企业,数据库对于业务的重要性不言而喻。
在引入oceanbase之前,三维家的数据库架构是典型的传统架构。最初,我们使用的是某关系型数据库。然而,随着数据量的快速增长,该数据库逐渐难以满足性能需求。因此,几年前,我们转而采取mysql分库分表的策略来应对日益增长的需求。
通过架构图可以看出,监控与运维分别在左右两侧,共同维护系统的稳定运行。核心架构位于中间,承载着系统的关键功能。当应用请求到达时,首先会通过负载均衡器进行分发,随后经过各种中间件进行处理,最终为了实现读写分离,这些请求会被进一步分发到mysql数据库和汇总数据库中。
在这一分库读写分离架构中,mysql的分库方案利用proxy sql作为中间件来代理数据库请求,同时采用了多重架构,细分为多个数据库,这是数据库表规模较大时的常见做法。在汇总库方面,由于分布式环境中可能涉及的haproxy场景中部分需求对实时性的要求较高,而分库架构无法满足这一需求,因此我们选用了一款国内知名数据库作为汇总db,主要负责处理读操作。
简而言之,先是写操作,随后是读操作。在读操作中,若涉及全局需求、类似haproxy场景,且对实时性要求高,无法直接由大数据后台处理时,通过汇总数据库实现快速查询。
业务挑战:三维家为什么从mysql分库分表走向原生分布式?
使用mysql分库分表策略替代旧有技术栈,虽然在短时间内帮助我们解决了日益增长的数据库需求,但仍在性能、运维和成本等方面存在各种问题。
第一,在性能方面,随着数据量的不断增长,mysql在处理大表时会遇到显著挑战。此外,复杂的查询操作也会导致效率低下。
第二,在运维方面,首先,架构复杂。三维家当前采用的一主多从、分库分表的架构,面临着一个特别棘手的问题,那就是大表之间的表结构变更。作为dba,大家可能深有体会,原本只需对一个表进行变更,但在分库分表后,这个操作可能演变成对几百个表的变更。这种操作不仅极其耗时,而且风险极高。
其次,实例/节点数量繁多,导致需要更多的第三方中间件来进行数据同步,比如读写分离和数据同步等。节点一多,潜在的故障点也就随之增多。特别是在数据同步环节,如果进行大表结构变更,很容易在同步过程中造成卡顿。一旦卡顿,后续数据读取的延迟就会大幅增加,进而影响到业务运行。
第三,在成本方面,采用分库分表方案,会显著增加上游机器的使用量。除了分库分表本身,还需增设中间组件及高可用系统,这些都需要额外的机器来安装和运行。因此,整体成本会大幅上升。
鉴于上述情况,我们开始考虑使用其他数据库作为替代方案,尽早整改和布局。而出于应对不断增长的数据量与日益复杂的业务需求的考虑,在进行数据库选型时,原生分布式数据库成为了我们的首选方案。
分布式选型:三维家为何选择oceanbase?
以原生分布式数据库作为首要前提,在技术选型上,我们着重关注数据库在以下几方面的能力与表现:
- 第一,技术过硬,确保具备强大的产品和技术能力。
- 第二,“一劳永逸”,希望通过一次选型和迁移能够满足三维家未来更长时间的需求,避免反复选型与重复投入。
- 第三,平滑改造,即兼容性。在进行数据库迁移和改造时,能够高度兼容mysql,避免硬开发投入大量资源,保证迁移项目的顺利推进。
在厘清业务需求、明确选型重点后,接下来我们针对典型操作,对当前几款流行的分布式数据库方案进行了全面的测试,通过各款产品在实际测试中的真实表现进行评定与对比,最终选择了oceanbase作为分布式数据库转型升级的方案。以下是各项测试内容与结果:
测试1:ddl变更对比
首先,基于当前的系统现状,选取大表进行测试。测试内容主要是针对一些常规任务,比如加字段、删字段,加索引等,通过测试,看看各数据库的表现如何。
- 第一,加字段。经过对比,我们发现,无论是mysql还是三维家之前用过的一款国内分布式数据库,在加字段这方面都有了很大的进步。不再像几年前那样需要建临时表等复杂操作,各测试对象现在基本都能在秒级完成。
- 第二,删字段。由于这类业务在三维家的场景较为罕见,因此在此次评估中,我们并未将其作为重点考量对象。
- 第三,加索引。由于新业务上线时,新增索引的需求往往比新增字段更为频繁,因此三维家对索引的添加特别重视。在业务实践中,我们发现oceanbase在索引管理上的表现比 mysql 8.0 快 1倍、比另一款测试对象快 15倍 以上,完全达到了三维家的预期,甚至在某些方面表现得更好。
测试2:数据压缩对比
数据压缩是oceanbase的一大亮点。在本次测试中,oceanbase 存储容量消耗不足 mysql的1/3,某db 的1/5.,也是我们关注的重点。图中所有数据都是真实测试得出的,这显然是节省成本的有力证据。
测试3:性能对比
在进行对比测试时,我们使用了线上实际的流量数据进行对比,某db规格为4台1.5t的96c192gb机器,oceanbase的配置为2台1.5t的62c400gb机器,测试结果如下图所示。
在对比测试中,我们发现oceanbase所需的机器硬件资源是三维家之前使用的某db的一半(oceanbase的核数相对较少,因其数据库特性, 故内存配置稍大)。随后,我们测试了不同并发量下的性能,从80个并发逐步增长到600个并发。在所有这些并发场景下,oceanbase的性能和效率均优于三维家原先的数据库。
测试4:线性扩展能力验证
除了横向对比,我们还对oceanbase自身进行了纵向对比。为了更好地了解oceanbase线性扩张能力,我们分别使用了不同的租户资源规格(从8c35g逐步增长到62c400g)来进行实际业务压测。
我们使用实际业务流量进行了对比,在对比过程中考虑了多种产品规格,目的是找到能够满足三维家业务需求,更加符合三维家业务发展的的产品。
我们使用实际业务流量进行了对比,通过测试得出结论:随着租户资源的提升,oceanbase性能不断攀升(62c的性能提升不明显是因为压测客户端已经到了性能瓶颈,无法提供更高并发压力)。我们的目的是找到能够满足业务需求且能够根据不同的业务需求选择不同规格的产品,以符合三维家的业务发展。
测试5:流量回放验证
我们更关心在真实业务场景下,oceanbase的性能表现,而不是tpc-c 理论极限值。我们选取了某个接口一天的业务流量,然后以不同的倍数进行流量回放,以获取oceanbase能支撑的最高qps,并验证在当前规格下是否可以承接当前线上业务的流量。在测试中,大约40个并发时,oceanbase就可以承接三维家峰值的qps,随着并发的不断加大,性能不断提升;在400个并发时,性能达三维家现有峰值的3倍;当并发达到600时,性能无法继续提升,这是因为压测机器已经达到性能瓶颈,由于峰值远超预期,我们就没有扩容继续压测。
因此,我们可以得出结论,oceanbase可以承接原有的业务流量。
三维家all-in oceanbase之路
三维家最早在2022年的9月至10月开始了对oceanbase的测试。
当初,我们只是初步了解到有一款刚开源的数据库产品,便开始去了解它。随后我们花费了近一年的时间进行各种充分的测试,以确保其稳定性和可靠性。
去年九月份,三维家决定将oceanbase应用于一个试点项目,经过几个月的稳定运行,我们对其性能充满了信心。随后,我们陆续将更多的数据库迁移到oceanbase上。截至到今年年初,三维家已经成功地将所有核心业务都迁移到了oceanbase上。
分享一些我们在迁移过程中发生的小故事。oceanbase提供了多种工具,包括评估和数据同步、数据采集等工具。然而,三维家的情况有些特殊,因为我们非常重视流量的实时回放功能,以保证我们能够在操作过程中不断优化。
在测试过程中,业务不仅要求一次性提供数据,还需在一段时间内实时回放流量。面对这一挑战,经过多番思考,我们选择利用流量抓取工具,将整个流程实现自动化。先抓取流量,实时分析出关键信息,再转发到新的数据库。这样就成功实现了实时回放功能,通过自主开发的小工具,最终圆满完成了任务。
考虑到新产品与旧产品存在差异,我们必须在这一阶段就着手对sql进行优化。此外,为了确保性能,sql的性能测试和索引准备也需提前完成。在完成了多轮前期准备后,我们终于开始切生产流量。下面展示了当时的真实案例截图。由于该业务仅涉及只读流量,三维家得以实现流量的分批切换,同时我们对流量进行按比例分配,逐步完成切换过程。以确保万无一失。
为了测试应用的响应时间,我们通过逐步增加流量的形式进行测试。首先上了10%的流量观察一天,随后第二天增至30%,之后调整为50%和75%。大约一周之后,我们将全部流量都切换到了oceanbase上。
同时,我们在应用端也进行了一个埋点的测试。在应用数据的下方,我们列出了响应时间,可以看出响应时间逐渐缩短。这表明,在切换到oceanbase之后,应用性能得到了显著提升,整体应用的响应时间更快了。
三维家为什么坚持all-in oceanbase?
当三维家all-in oceanbase后,收益发生了翻天覆地的变化。
目前,我们只保留了oceanbase,其他中间件基本都已去除,连监控也集成在oceanbase上了。这样,运维变得更简单,架构更简洁,故障点也自然减少了。现在,只需重点关注oceanbase即可。
关于oceanbase的显著特点,比如高性能和弹性,这些都是显而易见的优势,这里就不再赘述。对于原生故障转移功能,我们也专门进行了测试,例如手动关闭oceanbase的某个节点,以验证其是否能自动进行故障转移,测试结果也符合我们对高可用的要求。
关于成本方面,在引入oceanbase后,整体成本相较于原有架构减少了约30%。这是由于引入oceanbase后,其强大的分布式数据处理能力,让三维家可以去除分库分表的架构,从而节省了这部分成本。
在未来规划方面,近期我们团队也注意到云服务故障频频发生,因此提出了“异云多活”的战略目标,意味着我们不能将所有资源和业务都集中在单一云厂商上,以免一旦出现故障就无法运作。我们希望分散风险,确保业务的连续性和稳定性。
所谓“异云多活”策略,具体来说,如果三维家现在在使用a云,那么也必须在b云上部署相应的资源。这样,即使a云出现问题无法使用,三维家也能立即切换到b云,确保业务连续性。
要在之前的分库分表架构下实现多活运营,难度相当大,因为涉及众多中间件、组件和服务器,对多活运营的要求很高。但自从三维家采用oceanbase后,架构大大简化,有效帮助我们实现多活运营的目标。而且,oceanbase提供的oms工具非常强大,用户使用体验很好。目前,三维家已经初步构建了这种架构,预计在未来半年到一年内,就能完全实现异地多活的功能。
oceanbase运维经验总结
在迁移过程中,我们遇到了一些小问题和bug,大部分已经修复完成,在这里列出c7电子娱乐的解决方案供大家参考。
第一个问题,order by列提前校验(与mysql一致,与某db不一样)。
准确来说应为某db兼容性bug。在使用order by语句时,涉及一个字段,这个字段在两个表中都存在且值相等,但在order by后并未明确指定它属于哪个表。在我们之前使用的分布式数据库系统db中,数据是先被取出,然后再进行汇总和排序。在这种情况下,系统并不关心某一列数据具体来自哪个表。然而,在mysql的新版本和oceanbase中,系统在执行查询前会提前对这类情况进行校验。虽然这种情况大家可能不常遇到,但也可以简单了解。
强烈建议大家使用流量回放功能,我们常会通过它发现许多兼容性问题。这不仅在更换数据库或产品时会遇到,即便是从mysql 5.7升级到8.0这样的版本升级时,也可能出现类似问题。事实上,任何版本升级都可能伴随兼容性问题。更不用说,当涉及完全不同的架构或产品时,所谓“百分之百兼容”只是一种接近状态,实际上无法达到真正的完全兼容。
第二个问题,在数据库迁移或跨数据库操作的过程中,即使两个数据库中的某个字段被声明为相同的类型,并且从表面上看,从这两个数据库中检索到的某个字段的值也是相同的,但在应用程序中使用同一个函数对这些值进行处理时,可能会得到不同的二次返回值。
mysql将tinyint(1)识别成bit,做field.isbinary()返回false,而oceanbase 做field.isbinary()返回true;
例如,考虑一个函数,它检查从数据库中检索到的值是否为二进制类型,并根据这个判断来执行不同的逻辑。在mysql中,tinyint(1)可能不被视为二进制类型,因此函数可能会按照非二进制类型的逻辑来处理这个值。然而,在oceanbase中,同样的tinyint(1)类型可能被视为二进制类型,导致函数按照二进制类型的逻辑来处理这个值。这就会导致在不同的数据库环境下,即使输入值看起来相同,函数的二次返回值也可能不同。
第三个问题,oceanbase中in值太多,更容易走全表扫描,需绑定执行计划。
关于为什么要不断回放流量。原因就在于,不同的sql在不同的产品上可能会有不同的表现,这是合理且不可避免的。因此,三维家持续回放流量,以便及时发现并处理那些在游戏性能上存在问题的业务逻辑。
例如,在mysql数据库操作中,我们有时会遇到一些由业务逻辑组合而成的复杂sql。这些查询可能会涉及成千上万的数据行,这样的设计其实并不合理。在规范管理的公司中,通常会避免这种情况的发生。然而,由于开发团队水平参差不齐,有时会出现这样的代码编写情况。
这种情况会导致在选择sql的执行计划和索引时产生差异。因此,在大量的流量回放过程中,需要提前对这些sql进行干预。例如,可以提前为它们绑定执行计划,选定索引,以确保它们的执行效率和准确性。
例如,在mysql数据库操作中,我们有时会遇到一些由业务逻辑组合而成的复杂sql。这些查询可能会涉及成千上万的数据行,这样的设计其实并不合理。这种情况会导致在选择sql的执行计划和索引时产生差异。因此,在大量的流量回放过程中,需要提前对这些sql进行干预。例如,可以提前为它们绑定执行计划,选定索引,以确保它们的执行效率和准确性。