多平台融合——数据库HA(一)

2024-09-05 19:12
文章标签 平台 数据库 ha 融合

本文主要是介绍多平台融合——数据库HA(一),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

需求背景:在K8S集群中创建的微服务要使用浪潮云超融合上的数据库资源,为减少两个平台之间的耦合度,同时确保系统整体的可用性和安全性,做如下设计:

1、建立数据库主从集群,并将超融合中mariadb数据库视为主数据库,负责原平台的写入和读取业务,同时为其建立HA,确保主库的高可用性;

2、在K8S容器中建立多副本的mariadb数据库,并将其视为从数据库,与主数据库建立主从复制机制,确保数据的一致性。所有K8S集群上的微服务要访问超融合上的数据资源都通过从数据库访问。这样微服务中的数据或结构修改,不会污染到超融合平台上的数据库和应用系统,超融合上的数据更新又能及时同步到K8S集群中,减少了平台间的耦合度。

3、通过防火墙和istio网关设置两平台间服务通信及访问策略,确保两平台的安全性。

本篇只记录超融合上数据库HA的建立过程,其他内容后续再做记录。

数据库HA 前期准备

超融合上原有数据库为mariadb 使用docker创建,操作系统为ubuntu,虚拟机地址为21.12.3.81

1、在超融合中为其创建备份虚拟机可用地址为21.12.3.66(IP地址根据本单位实际使用情况分配),在虚拟机上安装docker 、docker-compose

2、为两虚拟机安装keepalived,配置虚拟地址,此处我使用的虚拟地址为21.12.3.75 

配置/etc/keepalived/keepalived.conf

vrrp_instance VI_1 {state MASTERinterface ens16virtual_router_id 71priority 101advert_int 1authentication {auth_type PASSauth_pass txgm2m85331919}virtual_ipaddress {10.12.3.75} 
}// 备份虚拟机上 priority 设置比101小就行,默认虚拟地址会飘到priority 值大的虚拟机上。

重启keepalived 服务,使用ip addr 命令查看虚拟地址是否起来

ip addr
2: ens16: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000link/ether 00:16:3e:8e:33:8c brd ff:ff:ff:ff:ff:ffinet 21.12.3.81/24 brd 21.12.3.255 scope global ens16valid_lft forever preferred_lft foreverinet 21.12.3.75/32 scope global ens16valid_lft forever preferred_lft foreverinet6 fe80::216:3eff:fe8e:338c/64 scope link valid_lft forever preferred_lft forever

3、在备份虚拟机上安装并启动mariadb

创建docker-company.yaml

version: '3.1'
services:mariadb:image: docker.m.daocloud.io/library/mariadb:10.5container_name: "mariadb-master"restart: alwaysenvironment:MYSQL_USER: "root"MYSQL_PASSWORD: "12345678"MYSQL_ROOT_PASSWORD: "12345678"MYSQL_REPLICATION_MODE: "master"MYSQL_REPLICATION_USER: "repluser"MYSQL_REPLICATION_PASSWORD: "12345678"command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --server-id=1 --log-bin=/var/log/mysql/mysql-bin --expire_logs_days=10ports:- "63306:3306"volumes:- /datas/mariadb:/var/lib/mysql- /home/shell/mariadb/log:/var/log/mysql

使用docker-compose up -d 运行,并查看容器运行情况

sudo docker ps
[sudo] password for shell: 
CONTAINER ID   IMAGE                                       COMMAND                  CREATED      STATUS      PORTS                                           NAMES
600ce3e8bf25   docker.m.daocloud.io/library/mariadb:10.5   "docker-entrypoint.s…"   6 days ago   Up 6 days   0.0.0.0:63306->3306/tcp, [::]:63306->3306/tcp   mariadb-slave

 配置mariadb主从复制

虚拟机中的mariadb HA,是通过配置主从复制实现数据同步的。

K8S中的数据库从库副本连接主库地址设置为21.12.3.75 ,这样只要两个虚拟机不是同时挂,就能保证主数据库的联通性。

配置21.12.3.81 数据库的 /etc/mysql/my.cnf --> 映射本地~/mariadb/conf/my.cnf

[mysqld]  
server-id = 1  # 这里的ID必须是唯一的,如果你在集群中设置多个服务器,每个服务器需要不同的ID  
log-bin = mysql-bin  # 启用二进制日志,并指定日志的前缀 
expire_logs_days = 10  # 可选:设置二进制日志的过期天数

sudo docker stop mariadb-master

sudo docker start mariadb-master

重启数据库 (这里的my.cnf是挂载到虚拟机本地目录的,如果不是挂载到本地,这种修改是不会生效的)

登录mariadb,创建主从复制账号,并授权

CREATE USER 'repluser'@'%' IDENTIFIED BY '12345678';
GRANT REPLICATION SLAVE ON *.* TO 'repluser'@'%';
FLUSH PRIVILEGES;

 查看主数据库binlog运行状态

show master status;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+------------------+----------+--------------+------------------+
| mysql-bin.000003 |      385 |              |                  |
+------------------+----------+--------------+------------------+
1 row in set (0.02 sec)

配置21.12.3.66 数据库

登录mariadb,配置从数据库连接主数据库信息

CHANGE MASTER TO
MASTER_HOST='21.12.3.81',
MASTER_PORT=63306,
MASTER_USER='repluser',
MASTER_PASSWORD='12345678',
MASTER_LOG_FILE='mysql-bin.000003',  //这里的值就为主数据库状态查询到的File值
MASTER_LOG_POS=385;  //这里的值就为主数据库状态查询到的Position值

启动slave进程,并查看slave状态

start slave;show slave status;// 如果能看到Slave has read all relay log; waiting for more updates这样的信息说明主从复制正常工作了//如果上面的MASTER_LOG_FILE或MASTER_LOG_POS值配置不对,会在状态中看到类似Got fatal error 1236 from master when reading data from binary log: 'Could not find first log file name in binary log index file'这样的信息可通过查询主数据库状态后,使用如下重新配置
stop slave;
change master to MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=385;start slave;
show slave status;

截止到现在HA中的主从同步已经建立,两个虚拟机中的数据库可以同步了,当一个虚拟机宕机,虚拟地址21.12.3.75会主动由21.12.3.81漂移到21.12.3.66上,由另外一台虚拟机上上的数据库持续工作,替代主数据库角色。但是要让K8S集群中的从数据库实现平滑切换,还需要解决一个问题就是从数据库的binglog pos值自动配置问题。这里需要解决两点:1、自动获取当前binlog状态值;2、主动同步并修改从数据库中的binlog状态值。

自动获取当前binlog状态值

在HA两虚拟机中安装inotify-tools、expect

编写脚本实现主库中的binlog pos值变化跟踪,并将其值发送到从数据库虚拟机上

因为使用docker 命令需要用到授权 ,存在交互式输入密码的问题,除了在主从数据库虚拟机上打通ssh的免密登录外,还使用了expect交互批处理命令

//文件名getbinlogstatus 
#! /usr/bin/expectset timeout 20
spawn sudo docker exec -it mariadb-master mysql -uroot -p12345678 -e "SHOW MASTER STATUS\\G"
expect { "*shell:" { send "passwordpassword\r"; exp_continue }  #passwordpassword是shell账号的密码"*password:" { send "passwordpassword\r" }
}
expect eof

chmod +x getbinlogstatus

//脚本文件binlog-sync.sh
#!/bin/bashexit_loop() {echo "monitor stop"exit 0
}trap exit_loop 2
# ctrl+c 退出程序
BINLOG_DIR="/home/shell/mariadb/log"
REMOTE_SERVER="21.12.3.66"while true; doecho 'passwordpassword' | sudo -S inotifywait -rm $BINLOG_DIR -e create,modify | while read path action file; doif [[ $file == mysql-bin.* ]]; then# echo "log changed: $file"/home/shell/mariadb/getbinlogstatus > /home/shell/mariadb/pos/mysql-bin.posscp /home/shell/mariadb/pos/mysql-bin.pos shell@$REMOTE_SERVER:~/mariadb/pos/mysql-bin-master.pos# /home/shell/mariadb/scpfiles $file $REMOTE_SERVERfidone
done

chmod +x binlog-sync.sh

./binlog-sync.sh 运行程序

然后用navicat等客户端软件登录mariadb对数据库操作,修改或添加数据,看21.12.3.66中 /home/shell/mariadb/pos/目录中是否有mysql-bin.* 文件,打开文件查看内容是否和21.12.3.81中show master status;查询到的内容一致,一致说明脚本正常工作。

配置HA中从数据库虚拟机中运行脚本

//脚本文件getbinlogstatus
#! /usr/bin/expectset timeout 20
spawn sudo docker exec -it mariadb-slave mysql -uroot -p12345678 -e "SHOW MASTER STATUS\\G"
expect { "*shell:" { send "passwordpassword\r"; exp_continue }"*password:" { send "passwordpassword\r" }
}
expect eof
//脚本文件nc-monitor.sh#!/bin/bashexit_loop() {echo "monitor stop"exit 0}trap exit_loop 2
# ctrl+c 退出
i=0
j=0
while true; doif nc -zv 21.12.3.81 63306; thenif [ $i -eq 0 ]; thenecho "21.12.3.81 畅通,复制slave状态"/home/shell/mariadb/getbinlogstatus > /home/shell/mariadb/pos/mysql-bin-slave-end.posi=1fij=0elsei=0if [ $j -eq 0 ] && [ -f "/home/shell/mariadb/pos/mysql-bin-master.pos" ]; thenecho "21.12.3.81 不通,复制master状态"cp /home/shell811127/mariadb/pos/mysql-bin-master.pos /home/shell/mariadb/pos/mysql-bin-master-end.posj=1fifisleep 1
done

chmod +x nc-monitor.sh getbinlogstatus

./nc-monitor.sh 运行脚本,关闭21.12.3.81上的数据库(当然这里是你的业务运行暂停数据库服务的前提下,进行的测试),可以发现21.12.3.66 下有:

shell@bigdatasvcdbs366:~/mariadb/pos$ ls
mysql-bin-master-end.pos  mysql-bin-master.pos  mysql-bin-slave-end.pos

就说明脚本正常工作了。

然后使用golang编写一个读取pos的守护进程,放在21.12.3.66上,便于K8S从数据库容器获取binglog的pos值,可通过http或grpc读取。这样就可以解决虚拟机主从切换,K8S从数据库连接同步的平滑切换。

核心代码如下供大家参考

// ms_type = 主从类型(master,slave)
func (r *binlogRepo) ReadBLS(ctx context.Context, ms_type string) (*biz.BLStatus, error) {var file_path stringif ms_type == "master" {file_path = r.data.binlogconf.MPosfile} else if ms_type == "slave" {file_path = r.data.binlogconf.SPosfile} else {return nil, errors.New(500, "NO_TYPE_ERR", "未设置主从类型")}fo := FilesOper{}lines, err := fo.ReadFileAllContext(file_path)if err != nil {return nil, err}var file, position stringfor _, line := range lines {idx_file := strings.Index(line, "File:")if idx_file != -1 {tmp := strings.Split(line, ":")if len(tmp) == 2 {file = strings.ReplaceAll(tmp[1], " ", "")} else {return nil, errors.New(500, "POS_FILE_ERROR", "pos文件损坏!")}}idx_pos := strings.Index(line, "Position:")if idx_pos != -1 {tmp := strings.Split(line, ":")if len(tmp) == 2 {position = strings.ReplaceAll(tmp[1], " ", "")} else {return nil, errors.New(500, "POS_FILE_ERROR", "pos文件损坏!")}}}if len(file) > 0 && len(position) > 0 {return &biz.BLStatus{file,position,}, nil}return nil, errors.New(404, "GET_POS_ERROR", "pos信息获取失败!")
}func (r *binlogRepo) CheckHealth(ctx context.Context, ms_type string) (bool, error) {var addr stringvar port int64if ms_type == "master" {addr = r.data.binlogconf.MAddrport = r.data.binlogconf.MPort} else if ms_type == "slave" {addr = r.data.binlogconf.SAddrport = r.data.binlogconf.SPort} else {return false, errors.New(500, "NO_TYPE_ERR", "未设置主从类型")}listener, err := net.Listen("tcp", fmt.Sprintf("%s:%d", addr, port))if err != nil {return true, nil}defer listener.Close()return false, nil
}func (uc *BinlogUsecase) GetBinlogStatus(ctx context.Context) (*BLStatus, error) {master_mysql_svc_status, err := uc.repo.CheckHealth(ctx, "master")if err != nil {log.Errorf(err.Error())}slave_mysql_svc_status, err := uc.repo.CheckHealth(ctx, "slave")if err != nil {log.Errorf(err.Error())}if master_mysql_svc_status {bl_status, err := uc.repo.ReadBLS(context.Background(), "master")if err != nil {log.Errorf("读取binlog pos 文件失败!%s", err.Error())return nil, errors.New(500, "READ_POS_ERR", fmt.Sprintf("读取binlog pos 文件失败!%s", err.Error()))}return bl_status, nil} else if !master_mysql_svc_status && slave_mysql_svc_status {bl_status, err := uc.repo.ReadBLS(context.Background(), "slave")if err != nil {log.Errorf("读取binlog pos 文件失败!%s", err.Error())return nil, errors.New(500, "READ_POS_ERR", fmt.Sprintf("读取binlog pos 文件失败!%s", err.Error()))}log.Errorf("主数据库库服务中断!")return bl_status, nil} else {log.Errorf("数据库HA服务中断!")return nil, errors.New(500, "MYSQL_SVC_ERR", "数据库HA服务中断!")}

这篇关于多平台融合——数据库HA(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1139829

相关文章

数据库面试必备之MySQL中的乐观锁与悲观锁

《数据库面试必备之MySQL中的乐观锁与悲观锁》:本文主要介绍数据库面试必备之MySQL中乐观锁与悲观锁的相关资料,乐观锁适用于读多写少的场景,通过版本号检查避免冲突,而悲观锁适用于写多读少且对数... 目录一、引言二、乐观锁(一)原理(二)应用场景(三)示例代码三、悲观锁(一)原理(二)应用场景(三)示例

Node.js 数据库 CRUD 项目示例详解(完美解决方案)

《Node.js数据库CRUD项目示例详解(完美解决方案)》:本文主要介绍Node.js数据库CRUD项目示例详解(完美解决方案),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考... 目录项目结构1. 初始化项目2. 配置数据库连接 (config/db.js)3. 创建模型 (models/

深入理解Apache Kafka(分布式流处理平台)

《深入理解ApacheKafka(分布式流处理平台)》ApacheKafka作为现代分布式系统中的核心中间件,为构建高吞吐量、低延迟的数据管道提供了强大支持,本文将深入探讨Kafka的核心概念、架构... 目录引言一、Apache Kafka概述1.1 什么是Kafka?1.2 Kafka的核心概念二、Ka

在Android平台上实现消息推送功能

《在Android平台上实现消息推送功能》随着移动互联网应用的飞速发展,消息推送已成为移动应用中不可或缺的功能,在Android平台上,实现消息推送涉及到服务端的消息发送、客户端的消息接收、通知渠道(... 目录一、项目概述二、相关知识介绍2.1 消息推送的基本原理2.2 Firebase Cloud Me

Spring Security基于数据库的ABAC属性权限模型实战开发教程

《SpringSecurity基于数据库的ABAC属性权限模型实战开发教程》:本文主要介绍SpringSecurity基于数据库的ABAC属性权限模型实战开发教程,本文给大家介绍的非常详细,对大... 目录1. 前言2. 权限决策依据RBACABAC综合对比3. 数据库表结构说明4. 实战开始5. MyBA

Ubuntu中远程连接Mysql数据库的详细图文教程

《Ubuntu中远程连接Mysql数据库的详细图文教程》Ubuntu是一个以桌面应用为主的Linux发行版操作系统,这篇文章主要为大家详细介绍了Ubuntu中远程连接Mysql数据库的详细图文教程,有... 目录1、版本2、检查有没有mysql2.1 查询是否安装了Mysql包2.2 查看Mysql版本2.

Oracle数据库常见字段类型大全以及超详细解析

《Oracle数据库常见字段类型大全以及超详细解析》在Oracle数据库中查询特定表的字段个数通常需要使用SQL语句来完成,:本文主要介绍Oracle数据库常见字段类型大全以及超详细解析,文中通过... 目录前言一、字符类型(Character)1、CHAR:定长字符数据类型2、VARCHAR2:变长字符数

Win11安装PostgreSQL数据库的两种方式详细步骤

《Win11安装PostgreSQL数据库的两种方式详细步骤》PostgreSQL是备受业界青睐的关系型数据库,尤其是在地理空间和移动领域,:本文主要介绍Win11安装PostgreSQL数据库的... 目录一、exe文件安装 (推荐)下载安装包1. 选择操作系统2. 跳转到EDB(PostgreSQL 的

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

C# WinForms存储过程操作数据库的实例讲解

《C#WinForms存储过程操作数据库的实例讲解》:本文主要介绍C#WinForms存储过程操作数据库的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、存储过程基础二、C# 调用流程1. 数据库连接配置2. 执行存储过程(增删改)3. 查询数据三、事务处