携程OceanBase开源实践——索引统计功能实现
【作者】
施纬,携程数据库研发工程师,主要负责数据库运维和内核研发。
姜贤富,携程高级数据库研发工程师,主要负责携程数据库监控运维及工具研发,拥有十年运维经验。
【概述】
自从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缺乏针对索引在使用上的监控,例如索引被引用的次数,一段时间内的频率,读写访问的次数等。这些统计数据对于数据库的运维是非常重要的,存在很多应用场景:
- 删除索引时需要确认索引是否被访问。用户一般通过创建索引来加速查询的过程,然而过多的索引,可能会占用过多的磁盘空间,查询时的索引选择和争用的开销也会上升,索引走错的概率也会增大,因此需要清理冗余索引。业务SQL发生变化时也可能需要下线老的索引,索引统计功能可以极大地降低删除索引的风险。
- 通过采集各个时间段的索引使用情况,我们可以感知整张表的访问热度趋势。例如图2中的例子,用户可以根据图中趋势分析出这张表的访问高峰时段,以及各个不同索引的访问趋势,在添加新索引后可以观察趋势验证索引效果,例如图中idx_b_c索引添加之后idx_b索引就逐渐不再被访问。
- 通过采集索引的读写访问次数,可以分析表的访问模式,以进行进一步的优化。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开源实践——索引统计功能实现的更多相关文章
- 实现携程X分钟前有人预定功能
实现携程X分钟前有人预定功能 原理:利用cookie与计时器两部分: 首先,进入页面,x会被随机数赋值,赋值后x会一分钟加1,直到加到60,再从1开始累加. 页面是否相同是根据页面的url后的id值判 ...
- 干货 | 质量保障新手段,携程回归测试平台实践 原创 Sedro 携程技术 2021-01-21
干货 | 质量保障新手段,携程回归测试平台实践 原创 Sedro 携程技术 2021-01-21
- ScaleFlux CSD 2000 在携程的应用实践
一.业界背景与现状 近些年来,有三件事实在业界同时发生: 1. 业务的发展朝着"生产"和"使用"海量增长数据的方向演进. 2. 摩尔定律 的 ...
- 携程React Native实践
React Native(下文简称 RN)开源已经一年多时间,国内各大互联网公司都在使用,携程也在今年 5 月份投入资源开始引入,并推广给多个业务团队使用,本文将会分享我们遇到的一些问题以及我们的优化 ...
- 携程酒店DevOps测试实践
作者简介 王幸福,携程酒店研发部高级测试经理,负责无线自动化测试相关工作.在测试框架和平台研发.移动测试.DevOps等领域有着丰富的经验. 如今很多大型互联网公司.创新型企业都在积极地进行DevOp ...
- 敏捷之旅--携程行程&订单团队
转自本人运营的公众号“ 携程技术中心PMO”(ID:cso_pmo) 关于我们 我们面临的挑战 敏捷开发是以用户的需求进化为核心,采用迭代.循序渐进的方法进行软件开发.先把一个大项目分 ...
- 开源实践 | 携程在OceanBase的探索与实践
写在前面:选型考虑 携程于1999年创立,2016-2018年全面推进应用 MySQL 数据库,前期线上业务.前端技术等以 SQL Server 为主,后期数据库逐步从 SQL Server 转到开源 ...
- 携程Android App插件化和动态加载实践
携程Android App的插件化和动态加载框架已上线半年,经历了初期的探索和持续的打磨优化,新框架和工程配置经受住了生产实践的考验.本文将详细介绍Android平台插件式开发和动态加载技术的原理和实 ...
- 携程实时计算平台架构与实践丨DataPipeline
文 | 潘国庆 携程大数据平台实时计算平台负责人 本文主要从携程大数据平台概况.架构设计及实现.在实现当中踩坑及填坑的过程.实时计算领域详细的应用场景,以及未来规划五个方面阐述携程实时计算平台架构与实 ...
- 携程App的网络性能优化实践
首先介绍一下携程App的网络服务架构.由于携程业务众多,开发资源导致无法全部使用Native来实现业务逻辑,因此有相当一部分频道基于Hybrid实现.网络通讯属于基础&业务框架层中基础设施的一 ...
随机推荐
- Keil MDK忽略警告, 包括文件末尾空白行, 未使用等警告
首先应该了解为什么Keil MDK 会有这样的警告, 原因简单说就是C99规定了要在末尾行加回车 一. 你可以使用格式化工具对所有源文件进行一次格式化处理. 二. 在Keil MDK中查看 Build ...
- 题解 CF980B
前言: 关于原题目中的 "旅馆" 这一用词,个人感觉用起来十分不畅,于是下文中将会用 "障碍物" 一词来代指旅馆. 题目大意: 有一座 \(4 \times n ...
- Nginx自定义日志中时间格式
背景 工作需要对接内部的日志中台,对日志打印有固定的格式要求,为了使Nginx的access日志也能被采集,需要对日志格式进行自定义,要求日志格式为: yyyy-MM-dd HH:mm:ss.SSS ...
- Codeforces #475 div2
题目链接:http://codeforces.com/contest/964 A题 答案n/2+1: B题 讨论三种情况 c>b c==b c<b C题 数论,逆元+快速幂,但是我一直卡在 ...
- Shell下处理JSON数据工具向导
目录 下载离线安装包 安装 源码包安装 选项及含义 JQ 程序代码演示在线平台 JQ 语法 基本过滤器 身份运算符 --- . 标识符-索引 --- .foo`, `.foo.bar 对象索引 --- ...
- System类的方法
1.exit() 2.currentTimeMills() 代码练习
- TypeScript核心基础
前言 为了方便我们直接使用脚手架让他帮我们直接编译就完事了 创建一个 Vue 应用 前提条件 熟悉命令行 已安装 16.0 或更高版本的 Node.js npm init vue@latest 这一指 ...
- Python 猫的 2023 年终回顾
2023 年是 Python猫 创办的第 5 年,2024 年已经到来了,我们照例做一个简短的年终回顾吧. 1.30000 订阅与 200 原创. 2020 的年终总结时,公众号订阅数刚破 20000 ...
- Python——第五章:模块(Module)、自定义模块、第3方开源模块、包(Package)
什么是模块(Module)? 在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护. 为了编写可维护的代码,我们把很多代码按功能分组,分别放到不同的文件里,这 ...
- 年底了,网站被挂马了,关于IIS被陌生DLL劫持(新人发帖,写的不好的地方,请多多担待)
一上班被分到两个需要杀毒的站点,情况是SEO被劫持 出现一些博彩信息,但是打开确实正常内容,使用站长工具的网站被黑检测功能,发现网站的HEAD前面加载一对加密的东西 一开始我使用D盾扫描网站,删除了一 ...