AnySQL.net

专注数据库TP领域25+年,Oracle、MySQL、DBA、架构师、MySQL内核研发!

AUL - 近20年历史的Oracle数据恢复工具

AUL(AnySQL UnLoader),又名MyDUL,是2005年深入学习Oracle数据库块格式时编写的软件程序,对标Oracle DUL,可以脱离数据库运行环境从数据文件中读取出记录。不象Oracle那样对数据文件非常严格的一致性检查,可用于极端情况下的灾难数据恢复。

从2005年到现在将近20年时间里,已经为全球30+个国家恢复过数据,在如下各种形形色色的故障场景下,都可以成功地将数据恢复出来,帮助减少企业数据相关损失。

  • 丢失整个SYSTEM表空间,或SYSTEM表空间不同程度损坏。
  • 意外删除用户或删除表空间,但保留数据文件,未被复用。
  • 表被删除(Drop)或截断(Truncate),及时备份了文件。
  • 磁盘介质或磁盘阵列错误,用户数据文件有不同程度损坏。
  • 数据库被黑客入侵,重要系统表(如TAB$)被恶意破坏删除。
  • 中招比特币勒索攻击,数据文件部份片段被加密无法访问。

支持Oracle 8i、9i、10g、11g、12c、19c、21c和23ai等版本,支持NUMBER、CHAR、VARCHAR、DATE、CLOB和BLOB等基础数据类型,支持Oracle ASM直接访问和恢复。可以下载Windows版本软件进行练习,详细操作可阅读AUL用户指南

如果你对自己的Oracle基础知识缺乏信心,可以将数据文件交给我们进行恢复。如果有些信心(可以提供持术支持服务),也可以提供长期许可(年度有效)或短期许可(一周有效),由你在本地机器上自行恢复,以确保数据安全。

工作 - 重新思考架构师工作与岗位

在上家公司工作时,兼了一个架构师的岗位,可能入职级别较高,内核研发工作宽度还不够。出于性价比考虑,业务主导的公司并不需要风口技术以外的深度技术人才,加些横向要求正常 。

架构师在很多公司已经消亡,哪怕是曾经有过架构师高光时刻的头部互联网公司。架构是一个动词,表示正在建设之中,所以要在建设过程中参与。自己当年正是学习eBay的Sharding体系经验后,来到只有两台小机的支付宝,经历了业务高速发展和大力建设的过程,才能有符合或部份超出期望的效果。

如果事后加入,要么能想出捷径,要么能救火!如果加入晚了,规模越大越难优化调整的成本,细节越多越难做救火英雄。这些事情都需要过去的积累,在现场深耕的人会有优势,并非架构师的善长。比如大量的业务研发在开发时默认备库无时延,既成事实之后,架构师能有什么捷径?有架构师可以在前期将问题提出来,没有架构师指导则会持续不断创造出这种难解的历史遗留问题。

在合适的时修提出合适的问题,是架构师的重要职责,这也是一件比较困难的事情。以大家熟悉的买房为例,过早买房付首付可能会占用过多的资金,当房价不涨时会有极大的资金垫付成本;过晚买房则可能房价上涨成本上升,甚至发展到再也买不起的阶段。架构师的岗位会变化,但架构相关问题值得留意和思考:

  • 研发默认备库复制无时延,业务代码逻辑又未做一致性检查?
  • 不同业务的数据库大表拆分维度各不相同,无规则也不整齐?
  • 对RPO/RTO无明确的事前取舍,常看事后责任大小灵活表态?
  • 对数十毫秒级的小抖动也无法承受,要求追责定位分析根因?
  • 同一个表的拆分既依赖应用路由又依赖DAL路由,不作收敛?

还有很多类似的问题可问,事后我没有能够想出低成本的解决办法,作为事后架构师,非常的无能为力。只抛出问题是没有用的,事后还是闭口比较好,说多了就成了人家自己早就知道的已知问题,只是在让人难堪而已。架构师只能在建设周期内,尽快取得对方信任,推动一些想法的落地。问题过时解决需要极大的资源成本,闲职既管不着资源又管不着考核的架构师非常不好胜任。

插件 - SharedServer高并发健康自保

插件本质上也是内核定制的一种,这里单拎出来讲,一方面是推广定制内核太难了,推广一个插件应当容易被接受一些;另一方面在MySQL现在的研发模式下维护定制内核的工作量有点大。这里讲的是纯插件机制,指的是可以在现成的二进制可执行文件下进行加载和卸载,不需要一起编译的,可以实现完全的干净的剥离。

SharedServer的基本功能和MySQL企业版的Thread Pool插件一样,可以进行替换。从2019年以Percona分支的Thread Pool版本(非插件机制)为基础进行研发,到现在也有近6年的时间,总共经历了以下几个版本变化:

  • 开源线程池版本稍作优化,默认不开启,不同操作相互阻塞。
  • 阿里云RDS版本,默认可开启,不同操作类型采用不同队列。
  • 美团RDS版本,高连接实例默认开启,优化Worker调度机制。
  • 可观测性版本,跨5.6/5.7/8.0版本统一会话、SQL性能视图。
  • 提炼SQL执行代价指标,基于代价做大小查询的分类及隔离。
  • 增加实时资源消耗指标,根据实时负载对大查询作并发流控。

可以看到,虽然SharedServer代码是重构的,但除可观测性和自动限流外的基础逻辑,已经过两大公司不同业务场景的持久考验,可以适应通用业务场景。使用SharedServer插件,可以规模化地解决并发引起的问题,已在真实场景中获得以下明显收益:

  • 静态内存节约,每个会话可节约160KB左右,减少OOM概率。
  • 应对突发流量,实现削峰填谷,减少活跃会话报警,更稳定。
  • 平衡动态内存,控制复杂SQL的并发度,内存涨跌幅度更小。
  • 突破线程限制,提高数据库总连接数上限,中小规格更明显。
  • 提升连接速度,生产环境每秒从1K到6K,应用发布更稳定。
  • 缓解读写干扰,独立读写队列分别控制并发,均衡持锁概率。

前面四点是在线上发现的业务可感知的真实收益;对于可观测性,主要是在定制的MySQL内核层做了更详尽的版本,所以作用不显;我们应当知道,5.6也还有业务在用,基本上没有性能视图可用;而在5.7上,开启PS的性能和内存代价比较高,一般情况下也是关闭的;8.0版本应当还没有成为存量业务的主流版本。因此MySQL上并没有特别好用的性能视图,在不定制内核的情况下,插件可以起到非常积级的作用。现提供如下RHEL/CentOS 7版本以便测试:

虽然插件是标准的,不同的MySQL版本,不同的OS版本,还是需要重新编译插件的,其中gcc工具和glibc库的版本需要保持一致。以上编译好的版本都是针对MySQL社区版的(无源码定制),如果是自己编译的二进制,则需要告知编译环境进行插件编译。

RPO - 尽早规划,数据分类

数据保护是一个容易讲不容易做的事情。说不需要付出实际代价,有相当多的严重案例可以引用,如同安全问题。做则需要付出额外的成本,包括多份数据的存储成本,包括本地落盘和远程跨机房落盘带来的响应时间(Response Time,简称RT)增加。RPO问题发生的条件相对苛刻,通常需要有一定的业务压力,并且需要原主库损坏无法访问,并且要损失到一定的数据量以上;但RT的增加就会给应用带来直接的非常明显的负面作用,并且频率会高得多。零RPO是业界公认难题,发生了还有借口挡一挡枪,严重问题通常由中上层领导担责;RT问题就直接是一线的能力问题,没有借口可言,所以一线选择多以RT优先。

从业务角度出发,每个不同的业务都会有部份数据需要很强的保护等级。一般来说余额类的数据保护等级要求最高,主要是没有其他系统可以参考校证。其次是交易流水类信息,出错后的用户体验不好,也可能造成资金损失,好在有上下游系统可以相互校验控制事态扩散;其他的如商品信息等等,保护等级要求较低,说几句好话让卖家或商家重新录入都是可行的手段。这里比较困难的是不同保护等级的数据可能是混合在一起的,每个数据库中都有一点保护等级要求特别高的数据,就需要每个数据库都开启半同步或切换到MGR,就会引起大面积的RT时延增加问题。比较推荐的做法是数据按等级分类存放,控制需要开启强同步模式的实例规模,保持总体RT增长不明显。

从技术角度出发,在不增加RT的情况下,尽可能保护事务日志不丢是重要的基础手段,可以用来分析丢失的数据范围,为此我们将MySQL IO线程的逻辑单拎出来做了一个性能极致的日志接收服务,再提高主库上Binlog Dump线程的CPU优先级,在工程上可以尽量做到事务日志不丢。半同步技术可以用于交易类数据的RPO保护,对于不同等级要求的数据混布的情况,也设想过一种按需半同步机制,即只有涉及到某些特定表的变更时,才需要等待从库ACK,否则可在主库上直接更新位点,以获取更好的RT时间。基于Paxos或Raft的强同步技术,则可以用于极少量的余额场景,考虑到此类产品的成熟度和掌控力,半同步调大超时时间后也可以顶一顶,此外业务逻辑中对于特定额度以上的操作,可以主动做一次备库访问检查,确保相关的记录在多个库落地后再继续。

工具 - 用自己的工具更顺手一些

SQLULDR2是一个2004年编写的小工具(Windows / Linux),强大的Oracle数据库并未提供将数据导成文本的工具,大概是进来了就不需要走的意思。由于Oracle数据库使用广泛,这个工具的下载使用量极高,我在软件的帮助信息中嵌了这样一条信息“License: Free for non-commercial usage, else 100 USD per server.”,但从来没有收到过,也没有人来问过100RMB行不行。Oracle 19c发布后,增加了对LOB类型LLS格式的支持,前段时间有人问有没有ARM的版本,有没有HPUX小型机的版本。有一个被人使用了20多年的小工具,才是最大的修行吧!

tpccmysql是一个Percona TPCC压测工具的改进版本(Linux版本下载)。有人讲这个工具的结果没有BenchmarkSQL好,分析后发现BenchmarkSQL有一步用了executeBatch接口,减少了非常多的网络交互,当然提速明显了。于是就顺着这个思路,将原来的单行更新多次交互,优化成IN或临时表关联操作,使得性能得到极大提升,轻松压到150万以上的TpmC值。象Oracle客户端本身就支持Array接口,可以进一步减少网络交互,优化应用是正常的行为。

mydbtest一个简洁的数据库压测工具(MySQL Linux版本),最早的版本是在Oracle上实现的,用来模拟业务SQL逻辑进行数据库容量评估。以交易创建为例,一笔交易涉及30个不同的SQL,那就将它们找出来写到配置文件中,定义好每个参数的数据生成规则,就可以直接开测,无须编程经验,当时DBA团队中就我能写程序。后来研发了MySQL版本,由于数据库规模越来越大,采用更为高效的流量录制和回放机制后,该工具用得不多。

骑行 - 健康减重的点点滴滴

大学毕业后一直没有认真思考过健康问题,也没有有意地去发现和培养一两种适合自己的锻练习惯,哪怕35岁前后突然发现熬夜能力激剧下降,40岁以后体检不正常指标项越来越多,都没有那么认真去思考,可能总觉得还有点年轻的资本吧。

直到父母不做生意回农村老家,正式开始考虑和承担他们的养老问题后,才发现70+的父母还能下地种庄稼,每次回家还可以带些自家产的菜和米回来,是一件多么幸福的事情。想想IT行业普遍的白头和秃发等异常现象,身体透支现象是普遍存在的,下一代又以独生子女居多,如何在身体健康上能与父母一样,让自己的子女将来可以安心在外,才认真起来。

过去一年,骑行相当坚持、有规律、有享受,是适合自己的运动(分三个阶段,待展开)。看到个骑行圈的说法,20岁是健身,30岁是保养,40岁是维修,50岁是抢救,感觉挺有道理的。

  • 2023年7月,团建拍到球状肚皮,忍无可忍、痛定思痛。
  • 2023年10月,进骑行群上骑行服,山地车勇登浙西天路。
  • 2024年4月,体重减轻,上公路车、锁踏和锁鞋,更享受。
  • 2024年10月,更换碳轮,多体验,更长时间保持3区心率。

在这里要充分感谢骑行群的年轻朋友们,在你们的带领和陪同下,一次又一次刷新着爬坡的高度和速度,路径也从50公里、100公里扩展到200公里,看到了不一样的风景,享受了不一样的激情。让我们一起坚持较劲下去,无论是在室外马路和还是室内台子上!

DAL - SDK过时,OneProxy入场

心里已将OneProxy放下好多年了,今天重新提及OneProxy是因为一个场景。场景是这样的,一个公司有非常多的业务应用,全部使用客户端SDK方式访问数据库,在应用研发初期默认了从库无时延(应是从单个写库开始,后来逐步扩从库分流),早期务量压力小主从无可观测到的时延,从未引起业务逻辑问题;随着系统及数据库的拆分和硬件的换代提升改善,一直将问题推迟到目前的规模才逐步暴发;但继续拆分的成本随规模同步变高,业务量继续缓慢上涨,问题逐渐明显起来。明确一下,这里讲的不是主从几秒几十秒的明显时延,而是上百毫秒就会有业务逻辑报错,接下来有什么好的可行低成本应对手段?

各主流开发框架自带的DAL层主要实现了数据库映象(Database Mapping)功能,将数据库的修改操作变成对象的CRUD,来避免在应用代码中直接编写SQL以提高效率和安全性。统常需要做三方面的定制,一是对流量转发进行有效管理,比如向业务提供透明的读写分离或分库分表功能;二是对接内部管理系统,以实现平台化管理;三是要对接HA系统进行数据源的状态管理。目前开源的基本上是做了抽取剥离的,功能上并不完善,一方面需要投入资源进行定制研发,另一方面客户端节点数变大后,版本升级越来越困难,一次滚动升级的时间得以年计。由于客户端节点数过多(几十万个),实时感知数据库主要时延就变得几乎不可能,将一个配置推送到所有客户端节点都可能要数分钟。想到这个场景后,发现OneProxy有以下几大优势:

  • 稳定性,多个场景布署运行近8年,各功能暂无未知问题。
  • 低时延,单核10万+SQL转发,8核单实例可支持50万QPS。
  • 多实例,内置集群模式多实例布署,应用可连任意实例。
  • 成熟度,功能完善,有一致性读写分离、分库分表等功能。
  • 可运维,不需要也不支持二次开发,通过管理端口轻松集成。
  • 实时性,实时感知后端负载和状态,前后端分离无痛切换。
  • 多语言,标准MySQL协议驱动接入,无需额外客户端定制。

简单来说,OneProxy的稳定性经过了时间考验,性能上持平SDK,功能上一致性读写分离可解上述场景,成熟度上无需二次内核研发,可运维性经过实践证明。可以下载软件阅读文档测试。

内核 - 开源MySQL定制路在何方

从商业角度来看,开源定制没有出路,不会有人认可和买单,虽然各家公有云上都有内核定制内容,但都难以单独计价产生研发收入,相继出现投入乏力现象。从技术角度来看,MySQL是使用极为广泛的基础组件,在使用中会遇到非常多的问题,或不合理的现象。有一些在内核中定制解决是最佳的应对方案,绕过去的成本极高。让我们从稳定性的角度出发,以DDL操作为样本一路扫下去,可以扫出些什么样的问题?

以DDL操作引起的主从复制时延问题出发,旁路的解决方案是使用gh-ost方案,此方案会将所有数据拷一遍,并且生成大量Binlog,不仅非常耗时,还有极多的额外IO影响SSD寿命,还会影响正常业务事务的提交速度,是非常不经济合理的方法。其根因是MySQL内核上很多问题未作最优解,由于DDL在从库串行执行,整个过程中主从复制时延持续增大,如果从库正在承担读流量,而应用又对复制时延比较敏感的话,就无法用高效简洁的源生DDL机制。这里可以想到如果DDL操作不引起数据重组,基本都可以Online操作,以添加普通索引为例,如果主从分别手工异步执行,不经过复制就不会产生复制时延,那么异步DDL就是一个有效的定制需求。

从DDL的执行时间比较长出发,DDL过程中通常需要扫描现有的数据,而MySQL的IO一个页面一个页面地下发的,在Oracle数据库中,一次IO请求可以访问多个连续的数据块,称为多块读,以提高IO的效率,这个方式对SSD和NVME也同样有效。因此多块读也可以是一个有效的定制需求,还可以扩展到有连续扫描的SQL中,其效果不仅限于DDL范畴。

在DDL的执行过程中,可能会短时间写入大量的数据,产生很多脏页,从而影响正常的查询请求,会因为得不到空闲缓存页面而变慢,这里可以思考MySQL内置的每秒和单页刷脏机制是否不够优化,有没有更合适的方法,Oracle数据库中有一个技术叫Object Flush,在DDL的过程中可以时不时地进行目标对象级别的刷脏,以防止单个DDL占用过多的缓存。

在DDL的开始和结束阶段,需要获得排它式的MDL锁,这里如果目标表有较长的事务,在开启DDL后将会阻塞后续的查询或更新操作,是否可以引入一种更温和的获取MDL写锁的机制,以防止出现长时间跌零的情况?这个优化在阿里云的月报中有提及并已实现,也是一个非常好的定制需求。

在MySQL 8.0的某个版本之前,表的Truncate、Drop或索引重建操作可能会引起剧列的性能抖动,其原因是需要将原对象留在BP中的数据页主动清空,可以去找一下相关的代码段,可以看到是从BP的头部开始持锁扫描数据页。假设这个表只有一个页面在缓存中,并且刚好在缓存列表的最后一个,则需要扫描整个BP。在找到一个页面并处理之后,又需要从BP头部重新扫描。这样明显不合理的逻辑,有没有优化空间?可以参考Oracle商业数据库中Object Checkpoint的概念。

还有极易想到的并行DDL问题,这个MySQL社区也已经想到并在8.0中实现了。在所有这些问题都解决之后,DDL是否可以完全不依赖gh-ost,而采用源生DDL呢,那也是不能的。因为还有需要重组数据的DDL语句,在生产系统中业务连续性的要求是极高的,只能用gh-ost或类似方案,既使是在80解决实时加列(Instant Add Column)后,也还可能会有重建主键的DDL操作。

在内核定制上,如果习惯成自然,会忽略很多可能的需求;如果不接受这个习惯,则可以发现很多技术上值得解的问题。但反过来问,既然有习惯可以接受这个现状,那么内核定制的业务价值如何定义呢?只能说,看到问题的全部是一个乐趣,去定制内核进行解决又是一种乐趣,不一定非要拿到全部乐趣吧!

自己维护了一个OneSQL分支,对TRX_SYS的锁进行了拆分,引入ReadView共享机制估化读写干扰,优化了事务清理(Purge)相关的流程,实现了百万TPS的主键更新能力,定制是可以将内核做到极致的,但不一定能找到业务场景进行验证,多少会失去一些定制的动力和乐趣。长期来看内核定制应是最优解,但在当前的形势下,企业节省开支降本更重要,内核定制还得继续苟着。

MGR - 尚需努力,持续改善

半同步一直以来并不是一个足够好的零RPO方案,主要在于切换本身需要依赖外部的HA机制,并且切换后不同节点的Binlog可能不一致,处理起来比较复杂,原Master可能需要回滚一点事务才能加回集群。所以MGR刚出来时给人耳目一新的感觉,也许是期望太高,也许是研发目标太高,直接面向了多点写入模式,低估了工程实现复杂度(想到某分布式数据库用透明分布式事务概念PPT来压底中间件分库分表的事情,现在好象不怎么提分布式事务了)。这么多年下来,MGR的推广不算成功。前公司曾经仓促推过一次MySQL 5.7 MGR,结果遇到了稳定性抖动、内存泄露、文件句柄泄露等问题,最后高效下线,都有心理阴影了。后来费了我好长时间去挑了一些合适场景重新上了一些量,并且加强了内核对MGR的投入,也没能彻底去除那个阴影。

比较出名的问题是认证信息的GC问题,认证信息只保存在内存中无持久化机制,并且源生代码固定了60秒才清理一次,又是用一把大锁来保护,所以压测中经常会看到每分钟严重抖一次,写压力较大时内存会持续上涨直至OOM为止。GreatSQL率先发力引入一个额外的数据结构将这个问题得到了极大的缓解,我们借鉴了这个优化思路,引入一个更轻量级的数据结构,并且对那把大锁进行了拆分,以更好的测试效果解决了问题。很难理解这么明显的问题,社区在8.0中也没有解决,8.4中也没有解决,看来社区对MGR的投入也是明显不够,需要自行加大投入持续完善了。

第二个是通信协议的问题,应当重构通信层,选用Raft协议(毕竞Oracle数据库都引入Raft机制了)并完全去除多写模块,只做简单高效的单主模式。社区在80版本上推出了一个稍微简化的单主模式,在性能和稳定性上提升不少。曾设想给RPO那里提到的日志接收服务增加Raft机制,但因为集群模式的变更需要底层平台做太多的适配,始终没有能够立起项来,始终觉得这是一个更好的解决方案,相当于用Raft构建一个专为Binlog设计的高效分布式存储,再加上Binlog协议的支持以简化外围接入,应当可以用一个统一的模式支持1-N个MySQL结点规模的集群。

第三个是测试用例的问题,随着MGR定制的深入,发现自带的测试用例,并不能得到较好的代码覆盖率,很容易发现一些低级问题。有一段时间团队成员有越研究越不敢用的情绪,已经在用的场景如果遇到问题还得解,当然也理解这样才能更好显示内核定制的价值,解决更多问题才有更多的成长空间。

Conatct by anysql(@)live.com, WeChat name anysql, or make a call to +86 159 256 11590