月度归档:2021年04月

MySQL/MariaDB主从、半同步复制原理

一、主从复制原理

当 MySQL 的 Master 节点的数据有更改的时候,Master 会主动通知 Slave,这时 Slave 开启一个 I/O thread 主动来 Master 获取二进制日志,向 Master 请求二进制日志中记录的语句;Master 将二进制日志中记录的语句发给 Slave,Slave 则将这些语句存到中继日志中,进而从中继日志中读取一句,执行一句,直到所有的语句被执行完。而经 SQL 语句从中继日志中读取出来,再一一执行的进程叫做 SQL thread;将这些语句执行完之后,从节点的数据就和主节点的数据相同了,这就是所谓的 MySQL/MariaDB 主从复制。

  • Master 节点必须开启二进制日志功能
  • Slave 节点必须开启中继日志功能
  • Slave 节点需关闭二进制日志功能(默认不配置即可)
  • Master 和 Slave 节点需要配置不同的 server-id
  • Slave 节点需连接到Master节点

二、半同步复制原理

默认情况下,MySQL 5.5/5.6/5.7 和 MariaDB 10.0/10.1 的复制功能都是异步的,异步复制的情况下可以提供最佳的性能。但是如果 Slave 节点没有接收到 Master 节点发送过来的 binlog 日志时,会造成主从节点的数据不一致,甚至在恢复时造成数据丢失。

为了解决异步复制的数据丢失的问题,MySQL 5.5 引入一种半同步复制模式,该模式可以让 Slave 节点接收完 Master 节点发送的 binlog 日志文件并写入自己的中继日志之后,给 Master 节点一个反馈,告诉 Master 已经接收完毕,这时主库线程才返回给当前 session 告知操作完成。当出现超时情况 ( 可配置 ) 时,Master 节点会暂时切换到异步复制模式,直到至少有一个设置为半同步复制模式的 Slave 节点收到信息为止。

半同步复制模式必须在 Master、Slave 节点同时启用,否则 Master 节点默认使用异步复制模式。

MySQL 的半同步是通过加载 Google 为 MySQL 提供的半同步插件 semisync_master.so 和 semisync_slave.so 来实现的。其中前者是 Master 上需要安装的插件,后者是 Slave 上需要安装的插件。
MySQL 的插件位置默认存放在 $basedir/lib/plugin

Redis Cluster + tomcat + mysql

背景

在架设国民认证服务的时候,国民认证厂家程式码是基于 Redis Cluster + tomcat + mysql 部署,因考虑到开发环境,我们要求快速部署、快速开发,所以,我考虑用 docker-compose 进行部署。

根据 Redis官网 的提示,为了让 Docker 与 Redis Cluster 兼容,需要使用 Docker 的 host 网路模式

环境

Docker version 19.03.8

docker-compose version 1.28.5

程式码如下:

version: "3.8"

services:
  redis-6371: # 服务名称
    image: redis # 创建容器时所需的镜像
    container_name: redis-6371 # 容器名称
    restart: always # 容器总是重新启动
    network_mode: "host" # host 网络模式
    volumes: # 数据卷,目录挂载
      - /data/docker-redis/redis-cluster/6371/conf/redis.conf:/etc/redis/redis.conf
      - /data/docker-redis/redis-cluster/6371/data:/data
      - /etc/localtime:/etc/localtime:ro
    command: redis-server /etc/redis/redis.conf # 覆盖容器启动后默认执行的命令

  redis-6372:
    image: redis
    container_name: redis-6372
    network_mode: "host"
    volumes:
      - /data/docker-redis/redis-cluster/6372/conf/redis.conf:/etc/redis/redis.conf
      - /data/docker-redis/redis-cluster/6372/data:/data
      - /etc/localtime:/etc/localtime:ro
    command: redis-server /etc/redis/redis.conf

  redis-6373:
    image: redis
    container_name: redis-6373
    network_mode: "host"
    volumes:
      - /data/docker-redis/redis-cluster/6373/conf/redis.conf:/etc/redis/redis.conf
      - /data/docker-redis/redis-cluster/6373/data:/data
      - /etc/localtime:/etc/localtime:ro
    command: redis-server /etc/redis/redis.conf

  redis-6374:
    image: redis
    container_name: redis-6374
    network_mode: "host"
    volumes:
      - /data/docker-redis/redis-cluster/6374/conf/redis.conf:/etc/redis/redis.conf
      - /data/docker-redis/redis-cluster/6374/data:/data
      - /etc/localtime:/etc/localtime:ro
    command: redis-server /etc/redis/redis.conf

  redis-6375:
    image: redis
    container_name: redis-6375
    network_mode: "host"
    volumes:
      - /data/docker-redis/redis-cluster/6375/conf/redis.conf:/etc/redis/redis.conf
      - /data/docker-redis/redis-cluster/6375/data:/data
      - /etc/localtime:/etc/localtime:ro
    command: redis-server /etc/redis/redis.conf

  redis-6376:
    image: redis
    container_name: redis-6376
    network_mode: "host"
    volumes:
      - /data/docker-redis/redis-cluster/6376/conf/redis.conf:/etc/redis/redis.conf
      - /data/docker-redis/redis-cluster/6376/data:/data
      - /etc/localtime:/etc/localtime:ro
    command: redis-server /etc/redis/redis.conf


  mysql:
    restart: always
    image: mysql:5.7.21
    container_name: FIDO_mysql

    ports:
      - 3306:3306

    environment:
      TZ: Asia/Shanghai
      MYSQL_ROOT_PASSWORD: Admin123

    volumes:
      - /data/FIDO/mysql/mysql.conf.d:/etc/mysql/mysql.conf.d
      - /data/FIDO/mysql/lib/mysql:/var/lib/mysql
      - /etc/localtime:/etc/localtime:ro
      - /data/FIDO/mysql/logs:/logs

  tomcat:
    restart: always
    image: tomcat:8.5
    container_name: FIDO_tomcat

    ports:
      - 8081:8080

    volumes:
      - /data/FIDO/tomcat/webapps:/usr/local/tomcat/webapps
      - /data/FIDO/tomcat/conf/context.xml:/usr/local/tomcat/conf/context.xml
      - /data/FIDO/tomcat/logs:/usr/local/tomcat/logs
      - /etc/localtime:/etc/localtime:ro
    links:
      - mysql:FIDO_mysql

docker配置代理

背景

在一些实验室环境,服务器没有访问外网的权限,需要通过http代理。我们通常会将网络代理直接配置/etc/profile的配置文件中,这对于大部分操作都是可行的。然而,docker命令却使用不了这些代理。比如docker pull时需要从外网下载镜像,就会出现如下错误:

$ sudo docker pull hello-world

Unable to find image 'hello-world:latest' locally
Pulling repository docker.io/library/hello-world
docker: Network timed out while trying to connect to https://index.docker.io/v1/repositories/library/hello-world/images. You may want to check your internet connection or if you are behind a proxy..
See 'docker run --help'.

解决方案

# 创建 /etc/systemd/system/docker.service.d
$ sudo mkdir -p /etc/systemd/system/docker.service.d

# 
$ sudo vim /etc/systemd/system/docker.service.d/http_proxy.conf
[Service]
Environment="HTTP_PROXY=http://${proxy-addr}:${proxy-port}/" "HTTPS_PROXY=https://${proxy-addr}:${proxy-port}/" "NO_PROXY=localhost,127.0.0.1,docker-registry.somecorporation.com"

# 更新配置并重启 docker 服务
$ sudo systemctl daemon-reload && sudo systemctl restart docker.service