一:读写分离

  - 概念

    -  读写分离的主要目标就是分摊主库的压力。

  - 基本架构

    -     - 

二:两种读写分离的架构特点

  - 客户端直连方案

    - 因为少了一层 proxy 转发,所以查询性能稍微好一点儿,并且整体架构简单,排查问题更方便。

    - 但是这种方案,由于要了解后端部署细节,所以在出现主备切换、库迁移等操作的时候,客户端都会感知到,并且需要调整数据库连接信息。

    - 你可能会觉得这样客户端也太麻烦了,信息大量冗余,架构很丑。

    - 其实也未必,一般采用这样的架构,一定会伴随一个负责管理后端的组件,比如 Zookeeper,尽量让业务端只专注于业务逻辑开发。

  - proxy 方案

    - 带 proxy 的架构,对客户端比较友好。客户端不需要关注后端细节,连接维护、后端信息维护等工作,都是由 proxy 完成的。

    - 但这样的话,对后端维护团队的要求会更高。而且,proxy 也需要有高可用架构。

    - 因此,带 proxy 架构的整体就相对比较复杂。

三:什么是“过期读” ?

  -  “在从库上会读到系统的一个过期状态”的现象,暂且称之为“过期读”。

四:处理 “过期读” 的方案?

  - 强走主库方案

  - sleep 方案;

  - 判断主备无延迟方案;

  - 配合 semi-sync 方案;

  - 等主库位点方案;

  - 等 GTID 方案。

五:强走主库方案

  - 原理

    - 强制走主库方案其实就是,将查询请求做分类。

    - 对于必须要拿到最新结果的请求,强制将其发到主库上。

      - 比如,在一个交易平台上,卖家发布商品以后,马上要返回主页面,看商品是否发布成功。

      - 那么,这个请求需要拿到最新的结果,就必须走主库。

    - 对于可以读到旧数据的请求,才将其发到从库上。

      -  在这个交易平台上,买家来逛商铺页面,就算晚几秒看到最新发布的商品,也是可以接受的。那么,这类请求就可以走从库。

  - 问题

    - 这个方案最大的问题在于,有时候你会碰到“所有查询都不能是过期读”的需求,比如一些金融类的业务。

    - 这样的话,你就要放弃读写分离,所有读写压力都在主库,等同于放弃了扩展性。

六:sleep 方案

  - 原理

    - 主库更新后,读从库之前先 sleep 一下。具体的方案就是,类似于执行一条 select sleep(1) 命令。

    - 这个方案的假设是,大多数情况下主备延迟在 1 秒之内,做一个 sleep 可以有很大概率拿到最新的数据。

      - 如如在客户端在下单完成后做1s的loading,其实等于变相的等待了从库1s。

  - 问题

    - sleep 方案确实解决了一定场景下的过期读问题。

    - 但,从严格意义上来说,这个方案存在的问题就是不精确。

    - 这个不精确包含了两层意思:

      - 如果这个查询请求本来 0.5 秒就可以在从库上拿到正确结果,也会等 1 秒;

      - 如果延迟超过 1 秒,还是会出现过期读。

七:判断主备无延迟方案

  - 原理

    - 通过 show slave status;结果

    - 

  - 对比  seconds_behind_master 判断主备无延迟(精度S)

    - 每次从库执行查询请求前,先判断 seconds_behind_master 是否已经等于 0。

    - 如果还不等于 0 ,那就必须等到这个参数变为 0 才能执行查询请求。

  - 对比 点位 判断主备无延迟

    -  Master_Log_File 和 Read_Master_Log_Pos,表示的是读到的主库的最新位点;

    -  Relay_Master_Log_File 和 Exec_Master_Log_Pos,表示的是备库执行的最新位点。

    -  如果

      - Master_Log_File == Relay_Master_Log_File

      - Read_Master_Log_Pos == Exec_Master_Log_Pos

      - 这两组值完全相同,就表示接收到的日志已经同步完成。

  - 对比  GTID 判断主备无延迟

    - Auto_Position=1 ,表示这对主备关系使用了 GTID 协议。

    - Retrieved_Gtid_Set,是备库收到的所有日志的 GTID 集合;

    - Executed_Gtid_Set,是备库所有已经执行完成的 GTID 集合。

    - 如果这两个集合相同,也表示备库接收到的日志都已经同步完成。

  - 小结

    - 虽然等待无延迟是可以解决问题,但是可能存在主备一直不一致,导致备库无法读取的问题。

    - 对比位点和对比 GTID 这两种方法,都要比判断 seconds_behind_master 是否为 0 更准确。

    - 这几种办法并没有达到 “精确” 的程度,可能存在 主库已经执行,但是还没有发送给备库的情况,导致过期读。(通过 semi-sync 解决)

八: 等主库点位方案 / 等GTID方案

  - 这两个方案都是 在备库执行,等待一定时间,如果在时间内 主库点位 / GTID 同步,则在备库执行,否则到主库执行。

九:小结

  - 这几种方案中,有的方案看上去是做了妥协,有的方案看上去不那么靠谱儿,但都是有实际应用场景的,你需要根据业务需求选择。

  - 即使是最后等待位点和等待 GTID 这两个方案,虽然看上去比较靠谱儿,但仍然存在需要权衡的情况。

    - 如果所有的从库都延迟,那么请求就会全部落到主库上,这时候会不会由于压力突然增大,把主库打挂了呢?

  - 其实,在实际应用中,这几个方案是可以混合使用的。

  - 比如,先在客户端对请求做分类,区分哪些请求可以接受过期读,而哪些请求完全不能接受过期读;然后,对于不能接受过期读的语句,再使用等 GTID 或等位点的方案。

  - 但话说回来,过期读在本质上是由一写多读导致的。

  - 在实际应用中,可能会有别的不需要等待就可以水平扩展的数据库方案,但这往往是用牺牲写性能换来的,也就是需要在读性能和写性能中取权衡。

《Mysql - 读写分离有哪些坑?》的更多相关文章

  1. 简单物联网:外网访问内网路由器下树莓派Flask服务器

    最近做一个小东西,大概过程就是想在教室,宿舍控制实验室的一些设备. 已经在树莓上搭了一个轻量的flask服务器,在实验室的路由器下,任何设备都是可以访问的:但是有一些限制条件,比如我想在宿舍控制我种花 ...

  2. 利用ssh反向代理以及autossh实现从外网连接内网服务器

    前言 最近遇到这样一个问题,我在实验室架设了一台服务器,给师弟或者小伙伴练习Linux用,然后平时在实验室这边直接连接是没有问题的,都是内网嘛.但是回到宿舍问题出来了,使用校园网的童鞋还是能连接上,使 ...

  3. 外网访问内网Docker容器

    外网访问内网Docker容器 本地安装了Docker容器,只能在局域网内访问,怎样从外网也能访问本地Docker容器? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Docker容器 ...

  4. 外网访问内网SpringBoot

    外网访问内网SpringBoot 本地安装了SpringBoot,只能在局域网内访问,怎样从外网也能访问本地SpringBoot? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装Java 1 ...

  5. 外网访问内网Elasticsearch WEB

    外网访问内网Elasticsearch WEB 本地安装了Elasticsearch,只能在局域网内访问其WEB,怎样从外网也能访问本地Elasticsearch? 本文将介绍具体的实现步骤. 1. ...

  6. 怎样从外网访问内网Rails

    外网访问内网Rails 本地安装了Rails,只能在局域网内访问,怎样从外网也能访问本地Rails? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Rails 默认安装的Rails端口 ...

  7. 怎样从外网访问内网Memcached数据库

    外网访问内网Memcached数据库 本地安装了Memcached数据库,只能在局域网内访问,怎样从外网也能访问本地Memcached数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装 ...

  8. 怎样从外网访问内网CouchDB数据库

    外网访问内网CouchDB数据库 本地安装了CouchDB数据库,只能在局域网内访问,怎样从外网也能访问本地CouchDB数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动Cou ...

  9. 怎样从外网访问内网DB2数据库

    外网访问内网DB2数据库 本地安装了DB2数据库,只能在局域网内访问,怎样从外网也能访问本地DB2数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动DB2数据库 默认安装的DB2 ...

  10. 怎样从外网访问内网OpenLDAP数据库

    外网访问内网OpenLDAP数据库 本地安装了OpenLDAP数据库,只能在局域网内访问,怎样从外网也能访问本地OpenLDAP数据库? 本文将介绍具体的实现步骤. 1. 准备工作 1.1 安装并启动 ...

随机推荐

  1. 多个List 或 Array 进行 合并

    1.调用 var aaa = new List<string>() { "0" }; var a1 = new List<string>() { " ...

  2. 1.xml解析

    public static void main(String[] args) throws DocumentException {         SAXReader saxReader = new ...

  3. 【多线程与并发】:Java中的锁

    锁的概念 锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁可以防止多个线程同时访问共享资源(但有些锁可以允许多个线程并发的访问共享资源,如读写锁). 在JDK1.5之前,Java是通过sync ...

  4. 范仁义web前端介绍课程---3、课程大纲(初步)

    范仁义web前端介绍课程---3.课程大纲(初步) 一.总结 一句话总结: 知识点脉络(知识架构):刚开始对这个稍微了解一下就可以了,在逐步的学习过程中,心里大概有这样一套知识点的脉络 二.范仁义前端 ...

  5. 进入tomcat6的控制台

      在tomcat文件夹找到conf文件夹中的tomcat-user.xml文件, 用记事本打开,在最下面可以看到tomcat默认把用户注释掉了,也就是说打开tomcat主页是进不去管理页面的. 方法 ...

  6. 模型稳定性指标—PSI

    由于模型是以特定时期的样本所开发的,此模型是否适用于开发样本之外的族群,必须经过稳定性测试才能得知.稳定度指标(population stability index ,PSI)可衡量测试样本及模型开发 ...

  7. 【E2E】Tesseract5+VS2017+win10源码编译攻略

    一,记录我目前在win10 X64和VS2017的环境下成功编译Tesseract5.0的方式: 二,记录在VS2017 C++工程中调用Tesseract4.0的方法: 三,记录编译和调用Tesse ...

  8. PLSQL流函数代码 540页 【我】

    540页 流函数代码 -- Create table create table STOCKTABLE ( TICKER ), TRADE_DATE DATE, OPEN_PRICE NUMBER, C ...

  9. .frm文件怎么导入到数据库

    如题想搞个私服游戏,但是数据库文件按文档的操作方法行不通.只能自行导入. 其实.frm文件就是mysql表结构文件,你拷贝data那一块的文件到你电脑安装的mysql的data文件下就行了. 一.首先 ...

  10. RabbitMQ 入门教程(PHP版) 第二部分:工作队列(Work queues)

    工作队列 在第一篇教程中,我们已经写了一个从已知队列中发送和获取消息的程序.在这篇教程中,我们将创建一个工作队列(Work Queue),它会发送一些耗时的任务给多个工作者(Works ). 工作队列 ...