【作者】

许金柱,携程资深DBA,专注于分布式数据库研究及运维。

台枫,携程高级DBA,主要负责MySQL和OceanBase的运维。

【前言】

   读写分离,是一种将数据库的查询操作和写入操作分离的方案,目的是为了降低读写操作的相互影响并提升资源利用率。在携程,读写分离的应用场景非常普及,只读的业务场景主要包括线上业务的读请求、缓存的拉取,大数据ETL取数等。

   OceanBase 数据库天然支持读写分离的功能,即通过 OBProxy 代理服务和OBServer的配置修改即可实现业务的读写分离策略;然而OceanBase 读写分离方案存在与业务耦合度过高、匹配不够灵活等问题。因此,我们在 OceanBase已有的读写分离方案下继续探索并优化更符合当前业务场景的解决方案。

一、OceanBase原生的读写分离策略

OceanBase数据库在读取数据时,提供了两种一致性级别:强一致性和弱一致性。

   强一致性指的是读取最新数据,请求路由给主副本;

   弱一致性不要求读取最新数据,请求优先路由给备副本。

基于此,通过应用侧为执行的sql添加sql hint来显性开启弱一致性读就可以实现基于注释的读写分离,同时也衍生出了如下三种常用的读写分离策略:

策略一、备优先读

通过修改obproxy的路由策略为follower_first,并将业务读流量指定到该obproxy从而保证读请求优先访问follower副本。



优点: 配置相对简单,只修改obproxy的配置,无需修改observer的配置;读流量均摊到全部follower副本上。

缺点: 读请求可能存在跨zone访问;在不调整副本leader的情况下,同zone或同server下不同副本的leader和follower可能共存,不能完全实现zone级别或者server级别的读写隔离。

高可用: 当两个follower副本中的一个宕机时,配置读写分离的obproxy将优先路由到另一个follower副本。

策略二、LDC(Logical Data Center)只读型副本

新增一个只读副本,为其添加idc标签,并将obproxy的参数proxy_idc_name指向该idc。指定读流量访问该obproxy,通过LDC配置仅访问只读副本。



优点: 读写完全隔离,读扩展性好。

缺点: 只读型副本只同步数据,不参与分布式选举,需要额外增加一个副本。对读请求不大的场景存在资源浪费。

高可用: 当只读副本宕机时,配置读写分离的obproxy将自动把流量切到其他follower副本上。

适用场景: 业务的读请求远大于写请求,且大部分读请求对实时性要求不高或者有大量的AP分析场景。

策略三、LDC(Logical Data Center)全功能型副本

将一个全功能型副本添加idc标签,驱逐该副本上的leader,并将obproxy的参数proxy_idc_name指向该idc。指定读流量访问该obproxy,通过LDC配置仅访问该副本,完全分离读写流量



优点: 读写完全隔离,且相对于策略二不需要额外资源

缺点: leader分布集中在两个zone中,有可能会降低写入性能

高可用性: 当指定idc侧的follower副本宕机时,配置读写分离的obproxy将自动路由到其他follower副本上。

适用场景: 读写比较均衡,存在少量AP场景

在满足读写分离需求的同时,我们也关心在使用这些策略时的高可用性:

   当只读节点宕机时,配置读写分离的OBproxy将自动修改路由,优先将读流量路由到其他follower副本上。在使用策略二或者策略三时,每一个partition只有单个的readonly或者follower副本承担读压力,因此切换到新的follower副本上的压力是可以负担的。

   当配置读写分离的OBproxy出现问题时,由于obproxy是一组无状态的服务,因此只需要依赖数据库访问中间件的判活来修改应用访问obproxy的入口即可实现高可用。

二、携程针对OceanBase在读写分离场景的探索

   上面三种策略,在不同场景下各有优劣,也都能达成读写分离的效果,但相较于前两种策略,我们更倾向于使用策略三。携程的业务场景中,大部分数据库的读写相对均衡,同时包含少量的etl取数、BI查询等场景,与策略三的适用场景更贴合,且成本相对较低。

   同时,我们也关注到oceanbase现有的读写分离策略中存在一个共性问题:应用侧必须为sql添加弱一致性读的sql hint,否则即使在obproxy做了相应配置,仍然不能达到读写分离的效果,所有读写压力将集中在leader副本上。这涉及到用户的代码改造且使读写分离策略与应用的耦合度高。因此,我们需要在已有方案的基础上,根据当前业务场景探索并实践出一个灵活的、与应用耦合度低的读写分离策略。

携程目前已接入OceanBase近百套集群,租户约140个,同时越来越多基于MySQL数据库的业务计划迁移至OceanBase 数据库。对于读写分离场景,迁移OceanBase成本较大。

针对需要保证OceanBase数据库适配当前读写分离场景的需求,我们首先梳理了携程业务目前读写分离的主要适用场景:

  • ETL取数:Zeus定时作业,需要将线上订单相关数据同步至Hive或ES
  • BI查询 Offline报表,为业务部门提供分析数据
  • MySQL业务中已存在的读写分离场景(如缓存拉取): 读请求远大于写请求的产品库场景,要求在延迟阈值内,将读请求路由到只读节点

我们看到携程现有的读写分离场景包含OLTP和OLAP,并且db涉及的业务线可能比较复杂很难简单分辨。

同时,读写分离改造涉及到增加sql hint /*+READ_CONSISTENCY(WEAK) */ 的问题 。sql hint在传统的关系型数据库中是一种通过注释的方式改写sql执行计划的设计,而在OceanBase中它同样有类似功能,并且提供了sql选择副本访问策略的能力。为了使弱一致性读生效,需要对有读写分离需求应用中的sql做如下改造:

  • Mysql原版sql
SELECT * FROM test
  • Oceanbase改造读写分离的sql
SELECT /*+READ_CONSISTENCY(WEAK) */ * FROM test

综上,在携程的业务上线或业务迁移过程中,容易遇到以下问题:

  • 现有业务迁移过程不透明,涉及业务层面的代码改造。
  • 代码和读写分离策略耦合,造成技术债。
  • DBA需要大量重新审核查询语句和业务行为,给出改造评估建议。

针对这些痛点,我们希望可以不使用sql hint,直接指定这些sql进行弱一致性读来达到读写分离的目的。我们开始调研能否在OceanBase代码层寻求解决方案。通过对源码研究,我们尝试在OBProxy组件上进行改造,最终实现不涉及用户代码改造前提下的自动开启弱一致性读功能。代码的改造包含以下两个方面:

  • 功能1、自动为访问本OBProxy的所有连接开启弱一致性读策略
  • 功能2、自动为访问本OBProxy的指定帐号(只读账号)开启弱一致性读策略

我们通过新增两个参数enable_weak_read和weak_read_user_list在建连时进行判断来分别实现上述两个功能。enable_weak_read参数开启时,将为访问该OBProxy的所有连接开启弱一致性读;weak_read_user_list参数则针对账号维度来指定部分账号进行弱一致性读。



以上弱一致性读策略均基于会话级别开启,通过配置LDC和read(slave)域名,进行读、写隔离,分担主库压力,自动实现读写分离策略,不需要人工干预。

三、携程针对 OceanBase 读写分离场景的实践和测试

对于obproxy进行改造后,为了验证其功能性,我们将其与LDC(Logical Data Center)全功能型副本读写分离策略相结合,进行了如下实验。

场景一:

leader副本集中在zone1,obproxy指定账号开启弱一致性读并且绑定idc2(zone2+zone3)



实验结果:zone1的流量消失,流量被zone2和zone3分摊

场景二:

Leader副本集中在zone1和zone3,obproxy开启对所有连接开启弱一致性读,并绑定idc2(zone2)



实验结果:zone1和zone3的流量消失,流量全部由zone2承担

四、携程选择的 OceanBase 读写分离场景

在携程现有的业务读写分离场景中,我们往往通过区分业务的账号来识别业务的行为,因此我们将obproxy上设置针对部分账号开启弱一致性读并将其中一个zone和proxy绑定来将这部分请求路由到指定zone上实现读写分离。

优点:

1、同一个集群的obproxy配置统一(不开启弱一致性读时LDC路由不生效),便于obproxy的横向扩展和快速切换应用流量的指向。

2、按照账号维度配置灵活度高,在部分极端场景方便人工介入。

五、总结

   我们根据现有oceanbase的读写分离方案通过优化obproxy源码,新增enable_weak_read和weak_read_user_list两个功能,在obproxy上直接实现读写流量的分离,解决了mysql迁移oceanbase过程不透明、用户代码与原读写分离方案耦合度高等痛点。为推动分布式数据库oceanbase适配携程当前业务场景,更好地在携程落地,走出扎实的一步。

Oceanbase读写分离方案探索与优化的更多相关文章

  1. sql server几种读写分离方案的比较

    在生产环境中我们经常会遇到这种情况: 前端的oltp业务很繁忙,但是需要对这些运营数据进行olap,为了不影响前端正常业务,所以需要将数据库进行读写分离. 这里我将几种可以用来进行读写分离的方案总结一 ...

  2. mysql 官方读写分离方案

    mysql 8.0 集群模式下的自动读写分离方案 问题 多主模式下的组复制,看起来挺好,起始问题和限制很多.而且中断一个复制就无法配置了 多主模式下,innodbcluster 等于是无用的,不需要自 ...

  3. EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~终结~配置的优化和事务里读写的统一

    回到目录 本讲是通过DbCommand拦截器来实现读写分离的最后一讲,对之前几篇文章做了一个优化,无论是程序可读性还是实用性上都有一个提升,在配置信息这块,去除了字符串方式的拼接,取而代之的是sect ...

  4. MySQL高可用读写分离方案预研

    目前公司有需求做MySQL高可用读写分离,网上搜集了不少方案,都不尽人意,下面是我结合现有组件拼凑的实现方案,亲测已满足要求,希望各位多提建议 :) 一.    网上方案整理(搜集地址不详...) 1 ...

  5. Mysql读写分离方案-Amoeba环境部署记录

    Mysql的读写分离可以使用MySQL Proxy,也可以使用Amoeba.Amoeba(变形虫)项目是一个类似MySQL Proxy的分布式数据库中间代理层软件,是由陈思儒开发的一个开源的java项 ...

  6. Spring+MyBatis实现数据库读写分离方案

    推荐第四种:https://github.com/shawntime/shawn-rwdb 方案1 通过MyBatis配置文件创建读写分离两个DataSource,每个SqlSessionFactor ...

  7. Mysql读写分离方案-MySQL Proxy环境部署记录

    Mysql的读写分离可以使用MySQL Proxy和Amoeba实现,其实也可以使用MySQL-MMM实现读写分离的自动切换.MySQL Proxy有一项强大功能是实现"读写分离" ...

  8. 数据库分库分表策略之MS-SQL读写分离方案

    MS-SQL读写分离将从以下知识点进行展开: 以下截图内容来自博主:https://www.cnblogs.com/echosong/p/3603270.html 1.本地发布(写库如:centerd ...

  9. mysql读写分离总结

    随着一个网站的业务不断扩展,数据不断增加,数据库的压力也会越来越大,对数据库或者SQL的基本优化可能达不到最终的效果,我们可以采用读写分离的策略来改变现状.读写分离现在被大量应用于很多大型网站,这个技 ...

随机推荐

  1. DIV 上下左右居中黑科技

    <style> #info{height:0px; width:0px;top:50%; left:50%;position:absolute;} #center{background:# ...

  2. AngularJS的核心对象angular上的方法全面解析(AngularJS全局API)

    总结一下AngularJS的核心对象angular上的方法,也帮助自己学习一下平时工作中没怎么用到的方法,看能不能提高开发效率.我当前使用的Angularjs版本是1.5.5也是目前最新的稳定版本,不 ...

  3. 面试--html语义化的理解和作用

    什么是HTML语义化 1.让开发者阅读和写出更优雅的代码2.让浏览器的爬虫和机器很好的解析 为什么要语义化 有利于seo方便其他设备监听 屏幕阅读设备 盲人阅读器方便团队协作开发 语义化元素 head ...

  4. Python窗口学习之给按钮美化

    tkinter的按钮很丑也很难改 怎么办呢? 最好的方法就是不用按钮! 给Label添加点击事件,和按钮的作用是一样的! 代码: #!/usr/bin/env python # -*- coding: ...

  5. vConsole移动端调试利器

    图示: ,  简单的几步操作: 1. 引入cdn     可以从https://www.bootcdn.cn/vConsole/下载,也可以下载保存在本地,直接引用 <!DOCTYPE html ...

  6. JavaScript实现按钮改变网页背景色

    运行效果: 源代码: 1 <!DOCTYPE html> 2 <html lang="zh"> 3 <head> 4 <meta char ...

  7. localStorage存储返回过来的对象 显示object object的问题

    localStorage.setItem() 不会自动将Json对象转成字符串形式 用localStorage.setItem()正确存储JSON对象方法是: 存储前先用JSON.stringify( ...

  8. springboot+maven实现模块化编程

    1.创建新项目repo-modele 2.右键Repo_modele -> New -> Module-->next 分别创建bs-web,bs-service,bs-entity, ...

  9. springboot集成spring security安全框架入门篇

    一. :spring security的简介 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下 ...

  10. Spring的事务控制-基于xml方式

    介绍:该程序模拟了转账操作,即Jone减少500元,tom增加500元 1.导入坐标 <dependency> <groupId>junit</groupId> & ...