【作者】

施纬,携程数据库研发工程师,主要负责数据库运维和内核研发。

姜贤富,携程高级数据库研发工程师,主要负责携程数据库监控运维及工具研发,拥有十年运维经验。

【概述】

自从2021年OceanBase开源以来,携程一直致力于其在实际业务场景下的应用实践,探索新一代分布式数据库的可能性。随着携程业务需求的增长和多样化,OceanBase的应用范围也越来越广,与之对应的,我们积累的实践经验也越来越丰富,希望进一步参与到OceanBase开源社区的建设中,推进国产分布式数据库的发展。其中,携程和OceanBase共同实现了索引统计功能,本文将介绍此次开源实践。

【开源共建】

经过2年的探索实践,携程已经形成了比较完善的OceanBase应用体系。2021年,我们将OceanBase初步应用于日志库场景,以评估OceanBase的性能、稳定性及数据压缩率。与此同时,我们进行了周边工具的建设,如发布工具,Canal工具等,并完善了标准化的上下线流程,为深化应用打下基础。随着使用流程的逐渐成熟,以及生产数据量的不断增长,我们拓展了OceanBase的使用场景,将其作为历史冷数据的归档库(见图1),利用其高压缩率节省85%的存储成本。如今,携程越来越多的业务场景使用OceanBase,如结算业务、推荐业务及其他在线OLTP业务场景,得益于分布式的扩容能力,我们可以更加轻松地应对各种高负载的情况。



图 1 OceanBase存储归档冷数据

除了体会到分布式数据库高性能、大容量、灵活扩展等优势外,我们也面临运维体系的挑战。因为我们已经有多年的MySQL使用经验,形成了相对成熟的MySQL开发和运维流程,所以我们在使用OceanBase时,希望它可以尽量兼容现有的各项开发、运维流程,包括数据库的上下线、表结构的发布变更、应用的访问方式、大数据取数等;还能提供超越MySQL的运维潜力。方便我们将OceanBase平滑接入现有的自动化运维系统,同时借助强大的分布式拓展能力进一步提升我们的运维能力。

对此,我们针对OceanBase建立了监控告警系统、慢日志审计系统、数据库迁移工具等,但在使用过程中,我们发现相比MySQL,OceanBase 4.2.1并不能完全满足我们的运维工作需求,例如没有提供类似MySQL的索引统计功能、详细的表级增删改查统计功能等。针对这些问题,我们向OceanBase团队提出了反馈,一方面我们希望OceanBase可以功能更加丰富,完全满足我们的使用需求,另一方面,希望参与分布式数据库的建设,为OceanBase社区贡献一份力量。

基于此,我们很荣幸和OceanBase团队达成了源码共建的合作关系,由我们提出需求协作开发并最终并入社区版源码,目前我们已在OceanBase 4.3中合作完成了索引统计功能(源码链接),下面就该功能的设计和实现进行详细的介绍。

【需求背景】

OceanBase 4.2.1缺乏针对索引在使用上的监控,例如索引被引用的次数,一段时间内的频率,读写访问的次数等。这些统计数据对于数据库的运维是非常重要的,存在很多应用场景:

  1. 删除索引时需要确认索引是否被访问。用户一般通过创建索引来加速查询的过程,然而过多的索引,可能会占用过多的磁盘空间,查询时的索引选择和争用的开销也会上升,索引走错的概率也会增大,因此需要清理冗余索引。业务SQL发生变化时也可能需要下线老的索引,索引统计功能可以极大地降低删除索引的风险。
  2. 通过采集各个时间段的索引使用情况,我们可以感知整张表的访问热度趋势。例如图2中的例子,用户可以根据图中趋势分析出这张表的访问高峰时段,以及各个不同索引的访问趋势,在添加新索引后可以观察趋势验证索引效果,例如图中idx_b_c索引添加之后idx_b索引就逐渐不再被访问。
  3. 通过采集索引的读写访问次数,可以分析表的访问模式,以进行进一步的优化。MySQL的索引统计功能就提供了表级别的读写统计数据,利用这些数据,用户可以采集每张表的读写访问趋势,从而判断这些表是读多写少还是写多读少等并根据访问模式选择更合适的优化方案,例如使用缓存、优化写入方式等。



    图 2 索引访问数据示例

传统的数据库MySQL和Oracle都提供了索引监控功能,前者利用performance_shcema中的内存表详细统计了每个索引被访问的次数及各种类型语句(增删改查)的执行次数,携程就是利用这些数据评估各个表的和索引的访问情况和负载类型;后者则将索引统计信息定期持久化到磁盘,DBA可以通过特定视图访问。

综上所述,我们认为索引监控功能对于OceanBase也是非常有必要的。

【设计方案】

为同时适应MySQL和Oracle模式下的用户访问,OceanBase索引统计功能采用持久化存储设计,数据存在内部表,两种模式下的用户可以通过不同视图访问;由于OceanBase是多租户设计,索引统计功能也需要具备租户级别的控制和统计能力;另外,为了尽可能降低性能影响,参考Oracle,该功能提供抽样统计模式选项。

如图3所示,索引统计采用增量数据写入内存,定期刷到内部表的方式实现,各个租户的增量数据、相关配置、定时任务以及内部表都是独立的。不同的SQL线程在访问到索引时会更新其租户下的索引统计数据,各个租户的定时任务会负责配置的刷新和内部表的更新,用户可以通过视图查询索引信息。



图 3 索引统计实现

【实现细节】

索引统计功能的主要流程可以抽象为三个阶段。

  • 数据收集:收集索引使用数据。
  • 数据管理:在内存中维护管理索引统计数据。
  • 数据上报:将收集到的数据持久化到内部表中。

图3中的流程就是这三个阶段的具体体现。另外,我们在实现的过程中也重点考虑了索引统计对数据库性能的影响,并进行了相应的优化。

【阶段1:数据收集】

考虑到兼容MySQL和Oracle的索引统计功能,收集的数据包括索引的使用次数、上次使用的时间、扫描的行数、各种类型查询的数量等。OceanBase 支持 SQL / OBKV(TableAPI) 两种方式对数据进行访问,数据统计需要考虑 SQL 和 TableAPI 两种访问形式。但由于 TableApi 使用与 SQL 模式不同的TableScan算子,ObTableApiScanExecutor 和ObTableScanOp,若在TableScan算子层统计索引使用,那么就需要分别适配 TableAPI 和 SQL 两种模式的算子;如果在更底层DAS层进行统计,则只能按分区粒度统计,无法获取表级数据。因此决定在TableScan算子层实现两种统计方式,在算子关闭时更新内存中的索引使用信息。目前,索引统计会收集索引的访问次数和访问时间。



图 4 索引统计数据收集流程图

【阶段2:数据管理】

各个租户会维护自身的索引统计数据,具体到内存中,增量数据储存在多个hashmap中,租户初始化时会根据自身的内存和CPU资源选择合适的hashmap数量来保证最优性能。索引数据更新时会随机选择hashmap写入数据,目的是降低并发访问时的锁竞争,同时数据采样也发生在此处,将根据租户配置的采样比随机写入数据。选择在写入时采样一方面可以减少性能影响和内存占用,另一方面不在数据上报时采样可以更精确地检测索引是否被删除。

【阶段3:数据上报】

租户内存中的增量数据会通过定时任务的方式写入内部表完成数据上报,该任务使用OceanBaseSharedTimer的方式实现,避免消耗额外的线程资源。上报过程中会对内存中每个hashmap进行全量的遍历,通过batch insert的方式将增量数据写入内部表,这个过程还会检查对应索引表是否已经删除,hashmap和内部表中的数据将在索引删除一段时间之后被删除。

【索引统计性能优化】

在开发和测试过程中,我们发现索引统计信息写入内存的过程有可能对整体的语句执行主流程产生性能影响。从图4的流程也可以看到,索引统计发生在整个语句执行的关键路径中,因此这一步的性能优化尤为重要。最开始我们采用单个hashmap进行数据存储,在数据上报时进行采样的方式。

由于统计是在TableScan算子关闭时写入hashmap,每次执行使用索引的语句都会对hashmap进行写入,在高并发访问相同的索引场景下,由于需要写入相同的hash桶,就会产生较多的锁竞争,从火焰图可以看到,整个调用栈中锁等待占用了较长时间。针对这个问题,我们和OceanBase的同学进行讨论后决定对hashmap进行分片,使用多个hashmap的方式来减少锁竞争,并将采样逻辑移到数据收集阶段,减少写hashmap的次数,这样一来,索引统计整体的性能影响就降低了很多。当然,用户也可以动态配置采样比例或者暂时关闭采样模式以获取更为准确的索引统计信息。



图 5 单Hashmap模式访问火焰图

【数据展示】

内部表:__all_index_usage_info

视图:DBA_INDEX_USAGE, CDB_INDEX_USAGE

内部表用于定时任务内部数据存储,视图则是呈现给用户使用,兼容Oracle的DBA_INDEX_USAGE字段,目前支持索引使用次数和使用时间的展示,后续可以进一步拓展。



图 6 索引统计视图示例

【展望未来】

本次开源共建,一方面丰富了OceanBase的功能,使其满足了我们的使用需求,另一方面也加强了我们团队的源码开发能力,为日后进一步的使用和共建打下了基础。非常感谢OceanBase团队提供的共建机会和技术支持,我们希望以后可以继续合作,共同推进国产分布式数据库的发展,实现共建共赢。

携程OceanBase开源实践——索引统计功能实现的更多相关文章

  1. 实现携程X分钟前有人预定功能

    实现携程X分钟前有人预定功能 原理:利用cookie与计时器两部分: 首先,进入页面,x会被随机数赋值,赋值后x会一分钟加1,直到加到60,再从1开始累加. 页面是否相同是根据页面的url后的id值判 ...

  2. 干货 | 质量保障新手段,携程回归测试平台实践 原创 Sedro 携程技术 2021-01-21

    干货 | 质量保障新手段,携程回归测试平台实践 原创 Sedro 携程技术 2021-01-21

  3. ScaleFlux CSD 2000 在携程的应用实践

    一.业界背景与现状 近些年来,有三件事实在业界同时发生:     1.  业务的发展朝着"生产"和"使用"海量增长数据的方向演进.     2.  摩尔定律 的 ...

  4. 携程React Native实践

    React Native(下文简称 RN)开源已经一年多时间,国内各大互联网公司都在使用,携程也在今年 5 月份投入资源开始引入,并推广给多个业务团队使用,本文将会分享我们遇到的一些问题以及我们的优化 ...

  5. 携程酒店DevOps测试实践

    作者简介 王幸福,携程酒店研发部高级测试经理,负责无线自动化测试相关工作.在测试框架和平台研发.移动测试.DevOps等领域有着丰富的经验. 如今很多大型互联网公司.创新型企业都在积极地进行DevOp ...

  6. 敏捷之旅--携程行程&订单团队

    转自本人运营的公众号“ 携程技术中心PMO”(ID:cso_pmo)     关于我们   我们面临的挑战   敏捷开发是以用户的需求进化为核心,采用迭代.循序渐进的方法进行软件开发.先把一个大项目分 ...

  7. 开源实践 | 携程在OceanBase的探索与实践

    写在前面:选型考虑 携程于1999年创立,2016-2018年全面推进应用 MySQL 数据库,前期线上业务.前端技术等以 SQL Server 为主,后期数据库逐步从 SQL Server 转到开源 ...

  8. 携程Android App插件化和动态加载实践

    携程Android App的插件化和动态加载框架已上线半年,经历了初期的探索和持续的打磨优化,新框架和工程配置经受住了生产实践的考验.本文将详细介绍Android平台插件式开发和动态加载技术的原理和实 ...

  9. 携程实时计算平台架构与实践丨DataPipeline

    文 | 潘国庆 携程大数据平台实时计算平台负责人 本文主要从携程大数据平台概况.架构设计及实现.在实现当中踩坑及填坑的过程.实时计算领域详细的应用场景,以及未来规划五个方面阐述携程实时计算平台架构与实 ...

  10. 携程App的网络性能优化实践

    首先介绍一下携程App的网络服务架构.由于携程业务众多,开发资源导致无法全部使用Native来实现业务逻辑,因此有相当一部分频道基于Hybrid实现.网络通讯属于基础&业务框架层中基础设施的一 ...

随机推荐

  1. 开发现代化的.NetCore控制台程序:(3)将nuget包发布到GitHubPackages

    前言 上一篇文章已经把项目模板的nuget包发布到了 nuget 的官方源了,其实还可以发布到其他源,比如 GitHub ,本文记录一下发布到 GitHub Packages 的过程. 注意:本文建立 ...

  2. 3.1 IDA Pro编写IDC脚本入门

    IDA Pro内置的IDC脚本语言是一种灵活的.C语言风格的脚本语言,旨在帮助逆向工程师更轻松地进行反汇编和静态分析.IDC脚本语言支持变量.表达式.循环.分支.函数等C语言中的常见语法结构,并且还提 ...

  3. 代码安全之代码混淆及加固(Android)🔒

    ​ 代码安全之代码混淆及加固(Android) 目录 代码安全之代码混淆及加固(Android) 摘要 引言 正文 代码混淆 代码加固 总结 参考资料 摘要 本文将介绍如何通过代码混淆和加固来保护An ...

  4. FPGA与Simulink联合仿真环境搭建(硬件在环)

    硬件在环(HIL) \(\quad\)官方的一些定义:硬件在环 (HIL) 测试是一种实时仿真,让您无需使用系统硬件即可开始测试嵌入式代码.如果正在开发的代码未按照规范运行,您可以通过此项测试来发现可 ...

  5. Android 11 后的应用数据和文件

    Android应用数据的保存方式有四种,分别是应用专属存储空间.共享存储.偏好设置.数据库. 应用专属存储空间 应用专属存储空间:存放应用专属文件,主要包括两个空间,卸载后移除 内部存储空间:位于系统 ...

  6. Java开发者的Python快速进修指南:异常捕获

    在之前的学习中,我们已经讲解了函数和控制流等基本概念.然而,在接触实际业务时,你会发现异常捕获也是必不可少的一部分,因为在Java编程中,异常处理是不可或缺的.Python的异常捕获与Java的异常捕 ...

  7. C#中的类和继承

    公众号「DotNet学习交流」,分享学习DotNet的点滴. 类继承 通过继承我们可以定义一个新类,新类纳入一个已经声明的类并进行扩展. 可以使用一个已经存在的类作为新类的基础.已存在的类称为基类(b ...

  8. 0x02.加密和编码

    识别算法编码类型 看密文位数 看密文特征(数字.字母.大小写.符号等) 看当前密文存在的地方(web.数据库.操作系统等) 密码存储加密 md5:16位和32位由0-9和a-f组成的字符串 ,该加密方 ...

  9. 后端程序员必会的前端知识-03:Vue2

    三. Vue 2 1. Vue 基础 1) 环境准备 安装脚手架 npm install -g @vue/cli -g 参数表示全局安装,这样在任意目录都可以使用 vue 脚本创建项目 创建项目 vu ...

  10. Socket.D 基于消息的响应式应用层网络协议

    首先根据 Socket.D 官网的副标题,Socket.D 的自我定义是: 基于事件和语义消息流的网络应用协议. 官网定义的特点是: 基于事件,每个消息都可事件路由 所谓语义,通过元信息进行语义描述 ...