写点什么

OceanBase 在科大讯飞三大场景下的应用实践

  • 2024-12-02
    北京
  • 本文字数:6409 字

    阅读完需:约 21 分钟

大小:3.36M时长:19:32
OceanBase在科大讯飞三大场景下的应用实践

作者|李梦嘉,科大讯飞技术中心数据库方向负责人。


作为亚太地区知名的智能语音和人工智能上市企业(股票代码:002230),科大讯飞自成立以来一直从事智能语音、自然语言理解、计算机视觉等核心技术研究并保持了国际前沿技术水平。2023 年,我们的某个 AP 业务进行数据库方案替换,上线了 OceanBase 数据库。本文分享这一年来 OceanBase 在科大讯飞的应用场景和运维经验。

数据库选型需求


2023 年,我们上线了一个全新的业务,短短几月,数据增长就远远超出了上线初的预测,以至于底层数据库 MySQL 支撑出现瓶颈。对此,运维侧和业务侧提出了不同的诉求。


首先,业务侧希望数据库具备 HTAP 能力和多模能力。


HTAP 能力。MySQL 数据库在我们生产环境中被广泛使用,既支持 TP 类在线业务,又处理 AP 类业务的数据统计与分析。众所周知,MySQL 对复杂 SQL 的优化能力较弱,当数据达到一定规模时就会出现性能瓶颈,这时开发人员需要找到一款性能更强的数据库,经过改造让其适配 MySQL。为了减少改造成本,我们希望有一款数据库既兼容 MySQL 协议,又能支持 HTAP 混合负载,最好一套系统代替 TP+AP 两套系统,无需分库分表,同时支持列存和行列混存及查询优化,以保障良好的查询性能。


多模能力。随着科大讯飞业务的多元化与复杂化,我们使用的数据库类型也越来越多,对开发、运维都是一种挑战。我们希望有一款数据库能够统一接口处理结构化、非结构化数据,简化我们的技术栈。另外,最好支持 NoSQL 功能,比如 HBase、Redis、向量等产品形态。


其次在运维侧,我们对数据库的诉求主要包括两方面:数据迁移、白屏运维。


数据迁移。由于我们使用的数据库类型较多,DBA 日常工作涉及在各个数据库集群中迁移、同步数据的操作,而使用的迁移工具、迁移方案也多种多样,因此,我们希望能有一款数据库支持 MySQL、HBase、Redis 、PostgreSQL 等多种数据库的数据迁移、同步,同时具备数据校验能力。


白屏运维。我们的运维工作也涉及平台化建设,在该平台尚未完成数据流转生命周期的覆盖时,就无可避免通过命令行黑屏去操作。进而产生误操作,给业务带来稳定性风险。我们希望通过白屏化运维包括安装部署、升级、备份恢复,以及集群巡检、故障分析、SQL 优化建议等功能,实现数据流转全生命周期的覆盖。


在做产品调研时,OceanBase 作为单机分布式一体化、TP 与 AP 一体化的数据库吸引到了我们,其兼容 MySQL 协议和部分语法,稳定性与性能已经过市场验证,近年来也拥有了多模能力。同时,OceanBase 拥有丰富的生态工具,在数据迁移和白屏运维方面页满足我们的要求。因此,我们决定引入 OceanBase(对选型和测试、上线过程感兴趣的朋友可以查看博文:亿级规模大表数据,查询性能快 40 倍|科大讯飞 HTAP 探索实践)。

OceanBase 落地场景


在业务上线 OceanBase 后,主要的应用情况体现在三类场景中。

场景一:海量数据统计

起初业务数据量很小,在线业务和统计业务共用一套 MySQL 集群,没想到上线不久后业务量猛增,增速远超产品侧的预测。



该业务有三个典型特点。第一,数据量大,核心表上亿级,最大的表超百亿规模;第二,增长快,核心表每天新增千万级数据,每年数据的存储量增加 5TB 以上,且不能删除,产品策略要求永久保存数据;第三,基于海量数据进行实时的多维度统计分析,要求秒级返回,并通过大屏进行实时展示(涉及报表 40+)。


这三个业务特性使 MySQL 面临两个支撑难点,一是大规模数据的迅速增长已经超出 MySQL 的承载力,二是 MySQL 在统计查询方面较弱,无法满足业务需求。为了解决这两个问题,我们对系统进行改造和拆分。


首先,为了解决 MySQL 单集群的容量问题,我们将与核心业务关联较低的表拆分到单独的 MySQL 集群中,再把纯用户文本类的大字段的表单独拆分到 MongoDB 集群,相当于缓解了 MySQL 容量瓶颈和水平扩展问题。


其次,把数据拆分到多个集群后,出于统计分析的需求,业务侧仍然需要将数据进行汇总,一种可行的办法是将数据抽取到大数据平台,通过平台进行查询。但是,这种方法的缺陷在于查询是异步进行,无法满足秒级查询和展示的需求,同时,数据流向大数据平台,也需要经过开发和改造。


为了减少开发改造的工作量,同时更好地解决问题,我们找到了兼容 MySQL 协议的单机分布式一体化数据库 OceanBase,并在 2023 年将其应用于海量数据统计场景。因为 OceanBase 支持水平横向扩容,所以容量不会成为业务发展的阻碍。同时,OceanBase 的 HTAP 特性,无论是 TP 场景的性能还是 AP 场景的统计分析都能够满足业务秒级查询的要求,在不同的统计 SQL 场景,相比 MySQL,OceanBase 的 OLAP 性能提升 7~40 倍。



最终,我们通过数据同步工具将 MongoDB 和 MySQL 多个集群的数据统一汇总到 OceanBase,在不改变业务逻辑的情况下,满足了业务统计查询报表的需求。

场景二:分库分表数据汇聚

对于一些规模较大的集群,我们在前期使用分库分表方案进行水平拆分,实际是将数据打散在多个分片上。比如将最大的表分成 16 个分库共 256 个分片。



在这样的架构下,做统计查询就比较困难。因为分库分表中间件对跨分片的关联和汇聚查询能力较弱,所以无法直接在中间件查询。如果采用人工查询和汇聚的方式,面对单表 256 个分片,耗时较长。另外,在进行 SQL 统计分析时,涉及亿级数量的表扫描,可能导致集群性能抖动,影响业务稳定性。


基于上述背景,我们将多个经过分片的数据汇聚到同一个查询库里进行统计,这是一个过渡方案,本质是使用 MySQL 多元复制的能力将多个分片的数据汇聚到一个 MySQL 汇总查询库,可以暂时满足业务需求。



但是,这个方案的数据同步链路非常复杂,因为我们业务环境中使用的是 MySQL 5.5,复制能力较弱,一些业务原因导致数据库版本无法升级和改造,所以数据必须经过一个临时的中转库,再结合 MySQL 5.7 的多元复制及 replicate DB 功能,把多个分片汇聚到一张表中。同时,每个分片都需要一个单独的同步链路,任何一个链路有问题,中转库及最终的数据查询汇聚库都要进行数据修复,导致整体链路出故障时难以修复。尤其是当线上需要变更表结构时。经过的每一个分片都要执行变更操作,致使汇聚链路中断,此时只能依靠人工修复链路。


更让人头疼的是,我们采用 MySQL 的源生同步,不支持数据校验,缺乏对已汇聚数据和源库原表的完整性校验的机制。如果同步链路中出错,我们只能选择忽略错误,继续保持链路的进度。因此,我们无法判定汇聚后的数据一致性和准确性,如果发现问题,只能重建同步链路,整个过程耗时又耗人。


为了解决上述痛点,我们使用了 OceanBase 的数据同步工具 OMS,代替中转库的方案。



OMS 对 MySQL 各版本兼容良好,可以让我们将数据从 MySQL 一步汇聚到 OceanBase,同步链路被极大地简化。由于 OMS 的监控和数据校验功能完善,可以监控各种数据延迟,便于我们及时获取同步动态,当数据出现冲突或丢失时,我们也可以借助工具快速进行修复。另外,上文提到每一个分片都是单独的链路,我们可以复制链路原子化,如果单一链路出现问题,也不会影响其他链路的数据同步。


下图是 MySQL 源生复制和 OMS 同步的功能对比,可以看到 OMS 占据很大的优势。比如支持断点续传、数据同步校验、同步延迟监控,以及当数据发生冲突时可以根据配置选择跳过还是覆盖。同时 OMS 也支持同步链路重建,当出现同步故障时,我们可以通过数据抽取快速恢复链路。



场景三:NoSQL 及多模

这是一个在线爬虫类业务,需要下载客户请求端的网页,并返回数据。该业务的并发很高,生产端和消费端的并发量均为 1.5 万个进程,同时业务对应用请求响应的时延要求是毫秒级,因此我们最初选择使用 Redis 去解耦生产端和消费端,使二者互不影响。


  • 通过 lpush 和 rpush 把待下载网页的 URL 数据存入 redis 的 list key。

  • 通过 lpop 和 rpop 来获取待下载的网页 URL。



由于爬虫的数据量特别大,整个 Redis 集群使用三台服务器,共 42 个实例,最大的单实例内存约 60GB,整个集群规模占内存约 2TB,这为系统埋下了隐患。


第一,Redis 主从复制是基于内存中的复制积压缓冲区,如果业务爬虫的瞬时写流量大,会把积压缓冲区的内存覆盖,导致内存不足,进而 Redis 主从复制中断,重建频繁失败。这时只能人工介入。


第二,由于爬虫数据的分布不均,整个集群中会存在热 key,业务对部分 key 请求频率过高时(>2w/s),会使集群负载不均。而且因为业务逻辑,我们没办法针对热 key 进行拆分。


第三,无论是生产还是消费,业务的并发量都很高,但 Redis 本身是单线程的,如果业务出现偶发 o(n) 操作就会导致单线程阻塞 :如 hgetall,scan, lrange 0-1 等。


因此,我们需要重新选型数据处理方案以解决上述难题。


OBKV 是构建在分布式存储引擎上的 NoSQL 产品,继承了 OceanBase 的分布式、多租户、高性能、高可靠等基础能力。其分为 OBKV-HBase 和 OBKV-Redis,后者正是我们当前选择的新方案,原因是:


  • OBKV-Redis 完全兼容 Redis 协议,业务侧不需要修改。

  • OBKV-Redis 持久化 key 到磁盘,解决内存不足或使用过多的问题。

  • OBKV-Redis 针对热 key 底层通过表分片进行了优化。

  • OBKV-Redis 利用 OBServer 多线程处理,无单线程阻塞问题。

  • OBKV-Redis 无特殊运维,只需运维 OceanBase 集群。

  • OBKV-Redis 的 P99 在 10 ms 以内,满足业务需求。


在上线前,我们针对 OBKV 和 Redis 进行了读写方面的压测,为了保证公平性,规格统一限定为 12 核 20GB。从下图可见,在读场景,二者的性能、延时相近。而在写场景,OBKV 写性能与 Redis 存在一定差距,但满足业务负载;OBKV 写延迟比 Redis 略高,但都在 10ms 以内,满足业务需求。



使用 OBKV-Redis 后,虽然性能与延时并未提升,但解决了此前 Redis 主从复制容易中断,产生热 key、单线程阻塞等问题。

OceanBase 白屏运维

除了上述应用场景外,OceanBase 丰富的工具体系为我们提供了极大便利。


本文开头提到复杂的运维操作促使我们寻找一个白屏化的运维平台,以管理数据库全生命周期。OceanBase 运维平台——OCP 基于 Web 的可视化白屏管理,将黑屏运维管理工作标准化、自动化,我们可以通过页面操作进行数据库运维,提升运维效率。


OCP 具有几项典型功能:

  • 资源管理。提供 OceanBase 集群,租户,主机等资源对象的全生命周期管理,包括管理,安装、运维、 性能监控、配置、升级等功能。

  • 监控告警。全局监控及告警设置,支持所有资源对象不同维度,实时、准确地监控告警需求,支持自定义告警。

  • 备份恢复。支持集群和租户表级全量备份、增量备份及日志备份,支持在备份周期内任意时间点的恢复,支持多种云平台介质的备份恢复。

  • 自治服务。自动化处理 “发现-诊断-定位-优化/应急”链路,极大地降低用户运维的成本。


从下面 OCP 平台的截图可以看到,无论是集群管理还是租户管理,我们部可以通过白屏化进行操作。在很大程度上简化了运维工作,降低了我们的运维投入。


OceanBase 运维经验

OceanBase 成功解决了我们在业务侧和运维侧的难题,在运维 OceanBase 一年后,我们也积累了一些运维经验,供大家借鉴。

1、产品版本选择

当我们在业务侧推广 OceanBase 时,通常业务侧会关心应该使用哪个版本,这时我们需要对各版本有较为全面的了解。OceanBase 的版本号通常有三类:


  • Va.b.c_CE,如 V4.2.1_CE;

  • Va.b.c_CE_BP1,如 V4.2.1_CE_BP1;

  • Va.b.c_CE_BP1_HF1,如 V4.2.1_CE_BP1_HF1。


在上述版本号中:

  • a 表示主要的大版本,一般会有架构升级或较大的新功能发布。

  • b 表示计划迭代版本,含有重要功能或特性更新和提升。

  • c 表示发布更新版本,对已知问题进行修复,一般无功能或特性变更。

  • BP:表示是第 X 个 Bugfix 版本,通常每个月发布一次,用于修复一些重大的 bug,引入一些小功能特性。

  • HF:表示是第 X 个 Bugfix 版本的第 Y 个 Hotfix,如果在 BP 发布期间发现了重大的 bug,就通过 HF 来修复。


目前,OceanBase 4.x 的长期支持版本有 OceanBase 4.2.1 和 OceanBase 4.2.5,我们使用的是 OceanBase 4.2.1。对于初次选择 OceanBase 的企业,我们推荐使用长期支持版本的最新 BP 或最新 HF 版本。

2、DDL 分类

在 MySQL 的日常运维工作中,Online DDL 操作或大表 DDL 操作对我们来说是一大痛点。OceanBase 对 Online DDL 操作进行了增强,目前 MySQL 中大表分钟级的 DDL 操作,在 OceanBase 中秒级完成,且不锁表,完全不会阻塞业务。不过,对于秒级完成的 Offline DDL :操作,其原理是新建一张临时隐藏表,后台将原表的数据补全到隐藏表,最后重命名临时表为原表并删除旧表,在这个过程需要锁表,对业务有损。

下图是 OceanBase 目前已经支持的 DDL 操作,相信随着版本的快速演进,Online DDL 操作会越来越多,Offline DDL:操作会越来越少。



此外,值得一提的是,为了解决 Offline DDL 锁表的问题,OceanBase 提供了一个功能——ODC 无锁结构变更。其本质是依赖 OMS、OCP 解决问题,首先创建临时表并改变表结构,其次全量拷贝数据并做增量同步和校验,最终切换新旧表。


下图是 ODC 无锁结构变更支持的变更范围。



在进行无锁结构变更操作时,我们需要注意:


  • 表必须有主键或非空唯一键;

  • 需要操作对象至少 2 倍的磁盘空间;

  • 无锁结构变更期间,其它关于该表的 DDL 变更将导致任务失败。


根据我们的实测数据,线网 5 亿单表(200GB)修改列类型耗时约 5 小时,但经过我们和官方技术人员分析,耗时较长的原因是 ODC 依赖的 OMS 同步效率慢,可以通过参数调优实现加速。

3、善用 Hint

优化器是数据库 SQL 执行的关键,但往往无法正确选择准确的执行时间。当优化器选择了错误的执行计划时,就需要通过 Hint 指定执行计划。Hint 是一种 SQL 语句注释,用于将指令传递给数据库优化器,使优化器生成指定的执行计划。一般情况下,优化器会为用户查询选择最佳的执行计划,不需要用户使用 Hint 指定。


下面来看一个简单的 SQL 在是否增加 Hint 的执行效率对比。该表的全量数据为 600 万行。虽然有围绕条件,但过滤条件不是很好,没有办法走索引。经过扫描,结果集也是 600 万,可以判定为全局扫描。

数据量:


obclient [oceanbase]> select count(1) from chat_req_uid_doctype_daily;

count(1)|

--------+

6097816

obclient [oceanbase]> select count(1) from chat_req_uid_doctype_daily where doctype in ('0', '1', '2', '3', '1100');

count(1)|

--------+

6025383


在不用 Hint 的情况下,初始 SQL 执行需要 6s,为了优化性能,我们为该 SQL 加入 Hint,执行效率提升至了 1s,效果较为显著。我们线网一般是把 OceanBase 作为一个 AP 类的场景去使用。所以说它的并发不是特别高。所以说在为了提升查询效率的情况下,我们一般会建议业务适当增加 Hint,因为 Hint 并不是越多越好,达到一定并行量后,性能提升效果会受限。


原 SQL(6s):


obclient [oceanbase]> select count(distinct uid) as uidcnts

from  chat_req_uid_doctype_daily

where doctype in ('0', '1', '2', '3', '1100');


添加 Hint 的 SQL(1s):


obclient [oceanbase]> select /*+ parallel(4) */

count(distinct uid) as uidcnts

from chat_req_uid_doctype_daily

where doctype in ('0', '1', '2', '3', '1100');

4、优化器版本对 SQL 的影响

不同版本的优化器,对 SQL 性能会产生不同的影响。举个例子,某 SQL 的条件列中是一个条件中的一个非相关子查询,最初我们使用 OceanBase 4.1.0 版本时,该 SQL 的执行时间为 0.3s,当我们升级为 OceanBase 4.2.1 版本后。执行时间退化到了 50s。


经过测试,发现问题在于条件列的子查询,如果把这个子查询换成子查询返回的固定日期,它的查询时间会恢复到 0.3s。这是由于数据库版本之间优化器的变化导致的,最终我们通过添加 Hint 并修改执行计划,使该 SQL 的执行效率重回 0.3s。


OceanBase 的优化器是基于规则优化和代价优化相结合,在一般情况下通过代价进行查询优化,可能会产生错误的执行计划,这时就需要通过 Hint 基于规则进行“修剪”实现优化。


目前 OceanBase 还在不断演进,其研发人员无法神通广大地覆盖所有 SQL 场景,还是要依赖于用户在生产场景不断发现问题、反馈问题,而官方的响应和改进也非常快速。期待 OceanBase 能够越做越好。


作者简介:


李梦嘉,科大讯飞技术中心数据库方向负责人。10 年以上 DBA 经验,对数据库的架构设计、优化、问题诊断、故障处理、数据恢复等有深刻地理解和实战经验。推动了讯飞数据库标准化、自动化运维、运维流程规范体系、高可用架构设计等建设。

2024-12-02 18:326980
用户头像
李冬梅 加V:busulishang4668

发布了 1181 篇内容, 共 803.2 次阅读, 收获喜欢 1300 次。

关注

评论 1 条评论

发布
用户头像
感觉TiDB才是最合适的选择
2024-12-03 13:55 · 四川
回复
没有更多了
发现更多内容

栀子花,我们应该像你一样静静绽放

小天同学

个人感想 感悟 日常思考

提升输入效率第一步——切换双拼

dongh11

效率工具 提升效率 生产力 分享 有趣

好的软件工程原则

pydata

健身一周年:持续锻炼带来无法想象的改变

小鲸数据

学习 职业 专注 健身

假如孔乙己是程序员

顿晓

学习 程序员 孔乙己

ARTS week 2

锈蠢刀

Android原生人脸识别Camera2+FaceDetector 快速实现人脸跟踪

sar

你的团队是干什么的?

姜戈

团队管理 团队职能

联邦学习与推荐系统

博文视点Broadview

人工智能 大数据 学习 推荐系统

码农远程办公指北

大伟

数据与广告系列三:合约广告与与衍生的第三方广告数据监控

黄崇远@数据虫巢

数据挖掘 互联网 广告 移动互联网

python实现·十大排序算法之计数排序(Counting Sort)

南风以南

Python 排序算法 计数排序

宕机原因千千万,被雷劈了最无奈

田晓旭

突破困局

Neco.W

感悟 工作 创业心态

点击劫持:无X-Frame-Options头信息(修复)

唯爱

软件开发生产率改进之我见(二)

清水

软件工程 软件开发 技术管理

一致性算法 Raft 简述

架构精进之路

raft 一致性算法

实现元素等高: Flexbox vs. Grid

寇云

CSS css3

揭秘神经拟态计算:缘何成为AI界新宠?

最新动态

Vol.1 Java初探,新手必看!

pyfn2030

编程 新手指南

源码分析 | Mybatis接口没有实现类为什么可以执行增删改查

小傅哥

Java 源码分析 小傅哥 mybatis 编程思维

redis过期策略和内存淘汰机制

wjchenge

100天从 Python 小白到大神最良心的学习资源!

JackTian

Python GitHub 学习 Python-100-Days Python-Core-50-Courses

你的团队想做出什么成果?

姜戈

团队管理

使用<input>标签实现六个格子验证码输入框

码上生长

Java vue.js 大前端

终于,我也到了和Eclipse说再见的时候,难说再见

程序员小跃

Java eclipse IDEA

Spring Security 两种资源放行策略,千万别用错了!

江南一点雨

Java spring springboot springsecurity

你为什么“啃不动”你手中的技术书?

图灵社区

Java Python 算法 HTTP R语言

你真的会用Mac中的Finder吗

Winann

macos 效率 App Mac

多线程与线程安全(实例讲解)

YoungZY

Java 多线程 线程安全

管理规划篇

姜戈

团队管理 团队组织

OceanBase在科大讯飞三大场景下的应用实践_数据库_李梦嘉_InfoQ精选文章