作者|曹佳俊,网易云信服务器研发专家
网易云信是网易集合 IM 与音视频技术打造的 PaaS 服务产品,为全球科技企业提供融合通信与视频的核心能力与组件。基于其丰富的服务场景与多样的业务需求,网易云信底层依赖多种数据库系统,以 IM 通讯系统为例,包括网易自研的关系型数据库 DDB,以及包括 Redis、HBase 和 Elasticsearch 等组件都扮演着重要的角色。在业务需求不断增长的过程中,数据库在性能、成本、高可用等方面遇到了问题和挑战。在本文中,网易云信分享了其 IM 通讯系统数据库的架构设计与优化实践,以及在关系型和 KV 业务场景中使用 OceanBase 和 OBKV 对现有架构进行升级与简化,从而在性能、成本、运维、高可用等方面实现有效提升的思考和实测经验。
网易云信是来自网易核心架构的通信与视频云服务,稳定易用且功能全面,致力于提供全球领先的技术能力和场景化解决方案。云信提供融合通信与视频的核心能力与组件,包括 IM 即时通讯和短信信令等通信服务,以及 RTC 直播、点播及互动直播等音视频服务。此外,网易云信结合网易易盾推出一站式安全通信方案——安全通。
目前,网易云信融合通信已接入 220 万企业开发者,全球注册应用数超 75 万,累计覆盖智能终端 SDK 数超 300 亿,月均消息量 3100+ 亿条,居行业首位,日活消息量表现突出。作为专为企业打造的融合通信的品牌,网易云信专注于文娱、社交、教育、医疗等行业,支持公有云、专属云、私有云与混合云四种部署方式。
对于如此体量的服务,数据库作为基石与支柱,扮演着极为重要的角色。随着业务规模的持续增长,我们也正在寻找一套适配网易云信业务场景的升级方案,在简化数据库系统架构、降低运维管理成本的同时,实现稳定提效。本文将分享网易云信数据库实践和运维经验,以及网易云信选型 OceanBase 背后的实践与思考。
网易云信数据库架构现状:需求复杂,种类繁多
在网易云信中,通讯和视频服务都高度依赖数据库,尤其是 IM 通讯系统。在 IM 通讯系统中,数据库种类较多。其中,最为重要的是关系数据库,也就是网易自研产品 DDB,它采用分库分表设计,专门用于存储 账号、关系和离线消息 等关键数据。其次,Redis 数据库、HBase 和 Elasticsearch 也扮演着重要角色。
DDB 是网易自研的分库分表中间件,目前在网易内部被广泛应用。不仅网易云信,网易云音乐、有道等众多产品也都深度依赖这套系统。
DDB 的架构是一个很经典的架构。首先,接入层我们称为 QS 服务器,这是一个 SQL-proxy。他的后端则是实际的存储节点,通常是 MySQL。接入层支持两种接入方式。一种是通过挂载四层负载均衡器,如 nlb 或阿里云上的 slb,来实现对 QS 的负载均衡和高可用。此外,对于 Java 程序,DDB 还额外提供了 lbd-driver 驱动。它的优势在于能直接连接 QS 服务器,并自动发现服务器、优雅地进行上下线管理以及故障转移。因为省去了 nlb 组件,也提高了效率和可靠性。
Redis 在网易云信 IM 系统中也占有重要角色,支撑着多种业务场景,我这边简单选取几个代表性的场景。
第一个场景是数据库缓存,基于自研数据库缓存框架,使用了简单的 KV 结构实现。它主要依赖简单的字符串操作,如 set/get/delete。特点是读多写少,且读操作的 TPS 很高。
第二个场景是在线状态管理,用于记录账号和设备的在线状态,使用 hash 结构记录多端登录和实现复杂的多端互踢策略,也是消息分发时的关键组件。简单讲,用户登录时系统会进行在线状态的写入与更新,而发送消息时则需查询在线状态。如下图所示,这是一个典型的读多写多场景,尤其在处理大群消息或批量消息发送任务时,读操作的 TPS 会显著上升。
第三个典型场景是漫游消息,从用户角度来看,它主要用于实现最近消息的多端同步功能。为实现这一功能,我们采用了 zset 结构实现先进先出的最近逻辑。该功能的一个显著特点是,由于需要存储最近发送的消息以便进行同步,因此其存储开销相对较大。这是漫游消息功能的现状。
此外,我们还引入了 HBase 和 Elasticsearch 数据库,主要用于存储和查询历史消息。HBase 的 row-key 全局有序的特点,非常适合适合根据时间进行历史消息分页查询的场景。而 Elasticsearch 被用于关键词检索等更复杂的搜索需求。为了降低存储开销,在 Elasticsearch 中我们并没有直接存储消息的完整内容,最终的搜索结果指向的是 HBase 中存储的消息。除了消息之外,用户和关系的检索等也会用到 Elasticsearch 相关的能力。
问题和挑战:业务需求与特定场景带来多样挑战
前面介绍了云信的数据库使用背景及现状,当前我们在使用数据库的过程中也面临一些问题和挑战。
关系型数据库 DDB:分库分表,特定场景仍存在瓶颈
首先,在关系数据库方面面临三个问题。
第一,性能瓶颈问题。尽管我们使用的分库分表架构已经相当稳定,并且依赖于内部强大的 owl 平台,能够自动化完成许多运维工作,如自动扩缩容、在线表变更等,但在某些特定场景下,我们仍然遇到一些瓶颈。为了进一步提升业务的灵活性和应对未来可能的扩展需求,我们希望能够引入原生的分布式数据库。这样不仅可以解决当前的性能瓶颈,还能为业务带来更多的弹性和可扩展性,这是我们最初的诉求。
第二,资源利用率问题。DDB 基于 MySQL 存储作为数据节点,其 B+tree 结构既有优势也有局限,这是众所周知的。在云环境下,我们期望在某些场景中能提高磁盘利用率,以实现降本增效。
第三,资源隔离功能。DDB 已提供一定程度的资源隔离能力,通过配置 policy 或者 schema 来实现。这些隔离策略能满足大多数业务场景的需求。然而,在某些特定的业务场景中,我们期望有更精细化的资源控制机制。现有的隔离机制可能是库表级别的,但我们希望它能进一步细化。对于云信这样一个多租户的 PaaS 系统来说,更细粒度的资源控制是很有必要的。
Redis:持续优化,业务增长带来更多挑战
其次,是 Redis
最初我们采用了开源的 redis-cluster 集群部署方案。Redis-cluster 本身是多节点且支持水平扩缩容的,在初期单集群即可很好的满足云信的单一业务需求。然而,随着业务的持续增长,由于 redis-cluster 单集群节点数的上限(我们单集群一般不超过 100 主 100 从),我们遇到了单集群下的内存容量瓶颈和 QPS 容量瓶颈。
为了突破这些瓶颈,我们开发了一个 Redis 代理,以实现更灵活的水平扩展。这个代理服务可以将多个 Redis-cluster 集群使用分片的方式透明的对外提供服务,从而突破单节点的规模上限。此外,为了更平滑在多个集群之间迁移数据,我们还在 redis 代理上实现了双写功能。
然而伴随业务规模不断扩大,云信的集群数量也随之增加,这让我们开始思考如何降低成本。特别是针对漫游消息这一业务场景。
漫游消息用于在相同账号的不同设备之间同步最近 n 天的消息,因此它有一个显著特点,用户通常会频繁读取最近的消息,而几天前的消息则读取较少。针对其特点,我们实施了一个冷热数据分离的存储策略。具体来说,我们将热数据存储在 Redis 中,以便快速访问;而冷数据则被持久化到 HBase 中。之所以选择 HBase 作为冷数据的存储介质,主要是因为当时我们有一套现成的 hbase 集群,dba 也有 hbase 的运维经验,此外 hbase 的扩展性也满足了我们业务增长带来的扩容需求。
我们发现冷热数据分离策略的效果相当不错。随即便开始思考如何将其打造得更加通用,不仅仅局限于漫游消息这一场景。为此,我们先将 Redis 中的冷热数据分离功能设置为可选,以适应那些 TPS 要求不那么高、希望所有数据都直接持久化在磁盘上的场景。
不久我们意识到持久化的 KV 存储不应局限于 HBase 这一种方案。因此,我们抽象出了一套通用的接口,使得替换存储方案变得更加简单灵活。这一改动上线后,云信的系统成功接入了更多业务,如在线状态发布订阅、云端会话列表等功能,都逐渐整合到了这套方案中。
值得一提的是,我们还开源了与这些功能相关的代码(开源地址:https://github.com/netease-im/camellia),有兴趣的朋友可以进一步了解。
目前线上我们主要使用 hbase 作为后端 kv 存储,然后由于其架构特性,宕机后的恢复时间可能会相对较长,基本要分钟级别。
另外,当我们通过 proxy 将 Redis 协议转换为 KV 协议时,会涉及将单个 key 的数据映射到多条 kv 的情况。这种转换过程中,数据不一致的风险是不可避免的,尽管并非所有场景都对数据一致性有严格要求,但这种风险确实存在。
此外,proxy 与 KV 存储之间的映射也会带来 proxy 和 kv-server 之间的多次网络 I/O,对性能造成一定的损耗。尽管我们做了很多优化工作来减少网络 I/O,但显然无法完全覆盖所有场景,性能损耗问题依然存在。
HBase:固有缺陷,故障恢复仍存在风险
在历史消息存储这一核心场景中,HBase 发挥了重要作用,挑战也随之而来。
起初,我们选择使用单个 HBase 集群来存储所有的历史消息数据,考虑到数据规模比较大,为了节约成本,便采用了 hdd 磁盘作为存储介质。然而,随着数据量的不断增长,HBase 也面临了一些挑战。特别是当某个节点出现故障后恢复周期相对较长,可能需要数分钟甚至数十分钟,这对业务运行造成了不小的影响。
为了应对这些挑战,我们后来决定采用双集群方案。在这个方案中,我们部署了两个 HBase 集群:一个是基于 hdd 的全量数据集群,另一个是基于 ssd 的小规模集群。ssd 集群用于存储最近一年内的消息,以提供更快的读写速度;而超过一年的消息则存储在 hdd 集群中,以节约成本。
对于写操作,我们采用双写策略,确保数据同时写入两个集群。对于读操作,如果查询的是最近一年的消息,则直接从 ssd 集群中读取;如果需要查询超过一年的消息,我们会从 hdd 集群中检索,并在业务层进行合并后返回结果。为了确保双写操作的一致性,我们引入了 Kafka 作为中间件。当向两个 HBase 集群写入数据时,如果某个集群写入失败,我们会通过 Kafka 记录这条失败的写入命令,并触发重试机制,以确保两个集群最终达到一致状态。
这个方案确实带来了不少优势,但同时也伴随着一些潜在问题,尤其是 HBase 架构本身存在的固有缺陷。
尽管我们已经将部分数据迁移到了速度更快的 ssd 上,但 HBase 的故障恢复时间依然是一个需要重视的问题。虽然相比使用 hdd 时,恢复时间已经大大缩短,但分钟级别的恢复时间对于实时性要求极高的业务来说,仍然可能带来不小的风险。
在这个架构下,随着业务的不断扩张,ssd 上的 HBase 集群所承受的读流量也在持续攀升。最初的设想中,在一个集群出现问题时,可以迅速切换到另一个节点以维持服务。然而,随着业务量的不断增长,特别是在高峰时段,这种切换策略变得愈发不可行。
具体来说,如果 ssd 节点发生故障时,切换到 hdd 集群是一个比较艰难抉择,因为我们不确认 hdd 集群是否能承担起流量,因此更多时候可能只能等待故障节点自行恢复。而这段等待时间,对于业务而言,可能就意味着服务质量的下降,甚至是有损状态。
鉴于上述数据库的这些痛点,我们开始寻找更符合业务需求的数据库。
技术选型:网易云信需要怎样的数据库?
在进行数据库选型的过程中,我们主要从兼容性和稳定性、平台统一性、成本、性能、高可用性、社区方面着重进行考量。
第一,稳定性和兼容性。这是我们着重考虑的因素。首先,稳定性至关重要,特别是对于云信的 To B 业务来说。鉴于云信拥有庞大的客户群体,任何微小的服务波动都可能迅速引发客户反馈,进而给前向团队和研发团队带来巨大压力。因此,稳定性无疑是数据库选型中的首要考量。其次,兼容性同样不容忽视。我们期望新数据库能够兼容现有 mysql 协议,以便业务能够顺利迁移,无需进行大规模修改。这样不仅能降低迁移成本,还能确保业务的连续性和稳定性。
第二,平台的统一性。如上文所述,当前许多数据库都具备多模和多功能的特点。我们期望新的数据库平台能够适应云信的多种业务场景,这样,在运维过程中,我们就能因为使用同一套系统而简化工作,进而降低运维成本。
第三,降本增效,特别是在数据存储方面。我们目前线上的数据库现状是,相较于存储需求,CPU 资源往往相对闲置。经常出现的情况是,CPU 还未充分利用,磁盘空间却已耗尽,且无法再增加磁盘。这时,云信不得不进行扩容。因此,如果能够通过利用 CPU 资源来换取存储成本的降低,对我们来说将是非常划算的。
第四,性能方面。虽然目前的 DDB 或 HBase 在性能上并未出现明显的瓶颈,但如果新数据库能进一步提升性能,那对我们来说无疑是更好的选择。
第五,高可用性的能力。这是我们曾经遇到问题,也是最希望得到改善的方面,特别是 HBase。我们期望新数据库具备可控的故障恢复时间,这能显著提升云信服务的整体稳定性。稳定性不仅体现在日常运行的无故障上,更体现在故障发生后的快速恢复上。恢复速度越快,云信的服务中断时间就越短,对于 To B 业务来说,这直接关联到成本节约。
第六,社区。我们期望使用的数据库,是一个社区活跃、功能持续迭代的现代数据库。这样,未来一旦我们有新的需求,能得到迅速响应和及时满足,这是我们非常看重的一点。
网易云信业务场景下 OceanBase 的优势:多场景降本提效
基于上述关于数据库技术选型的考量,OceanBase 在网易云业务场景中展现出显著优势。
首先对于关系数据库来说:
兼容 MySQL 协议。以关系数据库为例,我们特别欣赏 OceanBase 社区版对 MySQL 协议的兼容性,便于业务几乎无需修改即可平滑迁移。同时,我们的使用方式也无需做出特殊调整,大大简化了部署和运维过程。
成本优势,关于这一点,我们有坚实的数据支持,在后文中会详细展示。在采用 OceanBase 之前,我们曾对 MySQL 8.0 版本与 MySQL 5.7 版本进行测试、对比,虽然前者在压缩能力上有所进步,但与 OceanBase 相比,压缩效率仍显不足。
高可用能力。与 DDB 相比,OceanBase 同样具备出色的高可用性能。然而,DDB 的故障恢复时间依赖于 DDB-switcher 这一高可用切换工具,在最慢的情况下可能需要超过 1 分钟。相比之下,OceanBase 的故障恢复时间可以缩短至 8 秒,这一优势在我们多次实际测试中得到了验证。
原生分布式能力。与 DDB 这类分库分表中间件相比,OceanBase 在扩缩容时数据迁移更加高效。虽然 DDB 也能实现一定程度的自动化,但在资源依赖和操作流程上,OceanBase 显然更为便捷。
多租户能力。对于云信这样的 PaaS 平台,用户众多且使用习惯各异,有时难免出现个别用户行为异常,可能影响到整个系统。此时,OceanBase 的多租户资源隔离能力就显得尤为重要。通过 OceanBase,我们可以将云信业务中的不同租户数据隔离到各自的数据库实例中,实现资源的独立调度和管理。这样,即使某个租户出现异常行为,也不会波及其他租户或整个系统,从而显著提升服务的稳定性。这一底层逻辑的设计,充分体现了 OceanBase 在多租户资源隔离方面的独特价值。
性能优势。虽然 DDB 的性能对我们来说已经相当不错,但在某些特定场景下,由于其底层基于 MySQL,因此在单行更新等方面可能会遇到一些性能瓶颈。相比之下,OceanBase 在这方面进行了专项优化,表现更为出色。
单机分布式一体化特性,这一特性是 OceanBase 4.0 版本提出的,它为云信带来了显著价值。因为并非所有业务都需部署如 DDB 般庞大的数据库,尤其对于发号器、配置中心等轻量级服务,单机版数据库便足以应对。OceanBase 正是满足了这一需求,其一体化架构统一了底层数据库,极大简化了运维流程,对云信而言意义非凡。
对于 OceanBase 多模 KV 产品 OBKV,在网易云信的业务场景同样存在以下优势:
成本优势。相比 HBase1.x,压缩率显著提升,大大降低了成本。官方数据也证实了这一点。
高可用能力增强,这是我们尤为看重的一点。
接入较简单。官方提供了一个与 HBase 兼容的客户端 SDK,接入简便,因其与 HBase 客户端高度相似。
运维部署简单。OBKV 相比 HBase 极大的简化了部署,特别适合云信的私有化场景。
在私有化环境中,很多客户的需求并不需要大规模的部署。此时,如果采用 HBase 来处理历史消息,可能会显得过于庞大和复杂。
如果此时我们改用 OBKV,部署将变得非常简单,能够更好地实现公有云与私有化环境的功能一致性。在私有化环境中,由于无法部署 HBase,我们往往不得不割舍某些功能或采用其他方式实现,这不仅增加了开发成本,也损害了用户的体验。
采用 OceanBase 后,我们在私有化落地方面的挑战得到有效克服,实现了与公有云功能的一致性。OceanBase 相比 HBase 组件少、部署简单、运维方便,解决了私有化过程中的难点。
OceanBase 与 MySQL 对比实测:高压缩,高性能
在实践中,我们曾将线上数据库同步至 OceanBase 与 MySQL 8.0 进行对比测试。测试中,云信特别关注了核心大表,尤其是至关重要且规模庞大的离线消息表。OceanBase 的出色表现再次证明了其在处理这类核心数据上的卓越能力。
以下表为例,OceanBase 的压缩比高达 4:1 左右。相比之下,无论是页压缩还是大字段压缩,SQL 8.0 的压缩比都只能达到约 1.5 或更低,不超过 2:1。显然,OceanBase 在这方面具有显著优势。高压缩比直接转化为实实在在的成本节约,对云信而言意义重大。
此次单行更新测试,使用了 OceanBase 官方文档中的脚本。
结果显示,无论是低并发还是高并发场景,OceanBase 4.2.1 版本相比 MySQL 5.7 和 8.0 都表现出明显优势。尤其在并发增加时,OceanBase 的优势更为显著。这对于 IM 系统中需要单行更新的场景来说,将极大提升系统的稳定性。
单行更新测试
OBKV 与 Redis 对比实测:简化运维,高可用
前文提及新的 proxy+kv 架构,它经过简单改造后,目前已能支持多种 KV 存储,包括新的 OBKV 产品。OBKV 提供了 table-api 功能,并且已经开源。特别是,OBKV 最近发布了 4.2.5 版本,其中包含了 POC 版本的 obkv-redis 功能。我们已经基于这一 POC 版本展开了初步测试,并将持续关注官方对这一功能的后续优化与升级。
相较之下,OBKV 组件少,运维简单,降低了管理复杂度;高可用能力增加,故障恢复只需 8 秒,且性能提升明显。
下图是对一个简单字符串场景的性能测试,主要对比了 HBase、TIKV、OBKV 以及原生 Redis(通过 POC 版本)在 get/set 方法上的表现。我们使用了一个性能压测程序来进行测试。结果显示,OBKV 相较于云信之前使用的 HBase,在性能上确实有所提升。特别是在 P999 上的表现尤为突出。
对于复杂数据结构而言,OBKV 同样展现出了优势。这得益于它针对 Redis 数据结构进行的优化,使得其写入能力相较于 Redis-proxy+kv 架构更为出色。在读取方面,目前来看各种方案各有优劣,毕竟 OBKV 的这项功能刚推出不久,但是 obkv-redis 在部署上少了 2 台独立的 redis-proxy,我们也将持续关注其后续发展。
尤为值得一提的是,若我们采用 OBKV,并将关系数据库与 KV 数据库的底层全部替换为 OceanBase,将实现底层技术的统一。这一变革极大地简化了我们的运维工作,为系统维护带来了巨大便利。
OBKV 与 HBase 对比实测:性能显著提升
我们将 OBKV 与先前使用的 HBase 2.4.1 进行了对比测试。而线上之前实际使用的是 HBase-1.2.6 版本,性能可能更差。结果显示,在我们的业务场景下,OBKV 与带来了显著的性能提升,对业务产生了积极的影响。
未来展望
展望未来,我们将持续优化并推出新功能。
第一,逐步上线 OceanBase。目前,我们的测试工作正在紧锣密鼓地进行中,测试环境已搭建完毕并投入运行。会按照先部署 OBKV,再使用 OceanBase 替换 MySQL 的顺序逐步灰度和上线。当前部分业务已经正式上线使用 OceanBase。
第二,异地容灾。由于之前数据库底座的限制,云信的容灾方案相对复杂。在 OceanBase 的支持下,有望简化整个容灾方案。目前,我们正对此进行深入研究。
第三,迁移 obkv-redis。初期,我们可能会优先上线基于现有 redis-proxy+KV 的方案,只是将 KV 从 HBase 更换为 OBKV。我们会先运行这种方案,待其逐渐稳定后,再考虑迁移到 obkv-redis。
第四,使用 OceanBase 的 HTAP 功能。云信不仅拥有 IM 系统的核心在线功能,还集成了数据统计能力。当前,我们可能因系统分割,需借助数据平台和 CDC 来实现数据同步与数仓分析。若 OceanBase 的 HTAP 功能符合业务需求,将极大简化整体数据架构,促进系统间的高效集成。
另外,在测试过程中,我们对 OceanBase 提出了许多需求,都得到了 OceanBase 的积极反馈。未来也对 OceanBase 的新特性和新功能充满期待,最后祝 OceanBase 越来越好,谢谢大家。
评论