一个小实验,验证一个大受欢迎数据库的容器化
时下大受欢迎的数据库
笔者在IBM工作期间,曾进行过大量Oracle RAC的功能性测试,尤其是与双活存储的配合问题。而时下,随着技术的发展,分布式数据库越来越受到关注。MySQL已经排到了第二名:(参照https://db-engines.com/en/ranking):
而一份针对开发者的数据库调查显示,MySQL是最受欢迎的。
而目前,Docker、K8S技术非常火;那么,能否将大火的MySQL部署在大火的Docker+K8S以及时下挺火的Openshift中呢?
接下来,本文会对MySQL集群进行介绍,并通过实验方式,展示MySQL集群容器化的实现。
Mysql集群的实现方式
目前,MySQL集群实现方式主要有以下两种:
1. 主从复制
2. 基于Galera协议复制
基于Galera协议复制的方式,对应能损耗较大,本文篇幅有限,暂不进行讨论。
基于主从复制的Mysql集群,有三种配置方式。
- 一主一从
2. Master High Availability集群(MHA)
MHA(Master High Availability)目前在MySQL高可用方面是一个相对成熟的解决方案,是一套优秀的作为MySQL高可用性环境下故障切换和主从提升的高可用软件。在MySQL故障切换过程中,MHA能做到在0~30秒之内自动完成数据库的故障切换操作,并且在进行故障切换的过程中,MHA能在最大程度上保证数据的一致性,以达到真正意义上的高可用。
3. Master-Master replication manager for MySQL(MMM)
MMM(Master-Master replication manager for MySQL)是一套支持双主故障切换和双主日常管理的脚本程序。MMM使用Perl语言开发,主要用来监控和管理MySQL Master-Master(双主)复制,虽然叫做双主复制,但是业务上同一时刻只允许对一个主进行写入,另一台备选主上提供部分读服务,以加速在主主切换时刻备选主的预热,可以说MMM这套脚本程序一方面实现了故障切换的功能,另一方面其内部附加的工具脚本也可以实现多个slave的read负载均衡。
在以上三种模式中,双节点主从配置最简单高效;MHA最为成熟,MMM比较复杂,不建议使用。本文在接下来的实验中,先介绍基于容器的一主一从方式。
一主一从MySQL集群容器化实现
在实验环境中,笔者使用两个节点的Openshift 3.6(一个Opensift Master节点、一个Opensift Node节点),两个节点分别部署MySQL的Master和Slave。端口采用HostPort的方式(3306)。存储采用HostPath的方式,直接使用宿主机的本地目录:
首先,配置一个MySQL配置 Json文件(由于内容较多,只节选关键点)。
{
"kind": "Template",
"apiVersion": "v1",
"metadata": {
"name": "mysql-replication-openshift",
"annotations": {
"description": "MySQL Replication for OpenShift",
"iconClass": "icon-database",
"tags": "database,mysql,replication"
}
},
"parameters": [
{
"name": "MYSQL_MASTER_SERVICE_NAME",
"description": "Service name for MySQL master service",
"value": "mysql-master"
},
{
"name": "MYSQL_MASTER_USER",
"description": "The username used for master-slave replication",
"value": "master"
},
{
"name": "MYSQL_MASTER_PASSWORD",
"description": "The password used for the MYSQL_MASTER_USER",
"generate": "expression",
"from": "[a-zA-Z0-9]{12}"
},
{
"name": "MYSQL_USER",
"description": "The username that clients will use to connect to the server",
"value": "user"
},
{
"name": "MYSQL_PASSWORD",
"description": "The password for the MYSQL_USER",
"generate": "expression",
"from": "[a-zA-Z0-9]{12}"
},
{
"name": "MYSQL_DATABASE",
"description": "The name of the database that will be created and replicated",
"value": "userdb"
},
{
"name": "MYSQL_ROOT_PASSWORD",
"description": "The password for the root user",
"generate": "expression",
"from": "[a-zA-Z0-9]{12}"
},
{
"name": "VOLUME_CAPACITY",
"displayName": "Volume Capacity",
"description": "Volume space available for data, e.g. 512Mi, 2Gi.",
"value": "1Gi",
"required": true
}
],
"objects": [
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "${MYSQL_MASTER_SERVICE_NAME}",
"labels": {
"name": "mysql-master"
}
},
"spec": {
"ports": [
{
"port": 3306
}
],
"selector": {
"name": "mysql-master"
},
"clusterIP": "None"
}
},
{
"kind": "Service",
"apiVersion": "v1",
"metadata": {
"name": "mysql-slave",
"labels": {
"name": "mysql-slave"
}
},
"spec": {
"ports": [
{
"port": 3306
}
],
"selector": {
"name": "mysql-slave"
},
"clusterIP": "None"
}
},
{
"kind": "DeploymentConfig",
"apiVersion": "v1",
"metadata": {
"name": "mysql-master"
},
"spec": {
"strategy": {
"type": "Recreate"
},
"triggers": [
{
"type": "ConfigChange"
}
],
"replicas": 1,
"selector": {
"name": "mysql-master"
},
"template": {
"metadata": {
"labels": {
"name": "mysql-master"
}
},
"spec": {
"volumes": [
{
"name": "mysql-master-data",
"hostPath": {
"path": "/opt/mysql_data"
{
"name": "mysql-slave-data",
"mountPath": "/var/lib/mysql/data"
}
],
"imagePullPolicy": "IfNotPresent"
}
],
"hostNetwork": true,
"nodeSelector": {
"mysql-replica-node": "slave"
接下来,使用json文件创建template,然后部署template,生成两个pod:
MySQL集群创建成功:
接下来,查看Service ,因为容器使用HostNetwork方式,所以Endpoint的IP就是Openshift节点的IP。
Master:
Slave:
登录MySQL master的容器:
查看主节点状态:
在master中创建一个用户用于复制:
create user 'david'@'192.168.137.11' identified by '123456';
在master机上为slave机添加一同步帐号: grant replication slave on *.* to 'david'@'192.168.137.10' identified by '123456';
查看MySQL master配置文件:
binlog_do_db 指定需要同步的数据库,如果没有本行,即表示同步所有的数据库。
修改MySQL Slave的配置文件:
修改成如下内容,指定Master的IP,负责同步的MySQL账号、密码:
在Slave节点上执行,立即生效:
mysql> change master to master_host='192.168.137.11',master_user='david',master_password='123456';
确保从slave,用复制账号david可以成功登录master:
然后在slave上查看复制状态,一定要确保红色标识框里的两行全都是Yes状态:
如果 Slave_SQL_Running这一行是no,通常需要做数据同步:
在slave节点先执行 stop slave,然后在slave上执行(命令行中标黄部分的数值,在Master上执行show master status可以查看):
mysql> change master to master_host='192.168.137.11', master_user='david', master_password='123456', master_port=3306, master_log_file='mysql-bin.000006', master_log_pos=1172;
然后启动slave,再次查看,通常可以解决问题。
创建表测试,首先查看哪些数据库目前在复制状态:
使用mysql 这个database:
分别在master和slave上查看tables,得到结果相同,都只是包含默认的系统表:
接下来,在Master创建一个新的table zdavid:
到Slave上查看表,马上就可以看到:
我们查看Slave上的mysql log:
我们可以看到,slave执行了与Master上相同的SQL:
接着,在master上给tables插入一行数据:
到slave上查看数据库表,可以看到内容是一致的:
查看slave上mysql的log:
通过本文这个小实验,大家应该对MySQL在Openshift下的运行有简单的了解。至于很多人担心的容器化MySQL的性能问题,主要取决于底层持久存储的性能。
参考文献:
https://db-engines.com/en/ranking
http://www.cnblogs.com/lben/archive/2012/11/19/2777632.html
http://www.cnblogs.com/gomysql/p/3671896.html
- React多页面应用4(webpack自动化生成多入口页面)
- 第二周神经网络基础2.1 二分分类2.2 logistic回归2.3 logistic 回归损失函数2.4 梯度下降2.5 导数2.14 向量化logistic 回归的输出2.15 Python中的广
- 1031 SDIBT Where's Waldorf?
- poj 2469 Stack 'em Up
- React多页面应用3(webpack性能提升,包括打包性能、提取公共包等)
- POJ 2646 The Trip
- React多页面应用2(处理CSS及图片,引入postCSS,及图片处理等)
- 图的广度优先搜索和深度优先搜索(邻接链表表示)邻接链表广度优先搜索深度优先搜索运行结果
- JOJ 2680 Problem F: Coin Game
- React多页面应用1(webpack开发环境搭建,包括Babel、热更新等)
- JOJ 2676 Problem B
- React项目配置2(自己封装Ajax)
- React项目配置1(如何管理项目公共js方法)
- c++中stack、queue、vector的用法一、栈(stack)二、队列(queue)三、向量(vector)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android实现WIFI和GPRS网络的切换
- 在VS2010里快要疯掉的hello world
- gh0st源码分析与远控的编写(三)
- Android自定义View实现五星好评效果
- Android通过ViewModel保存数据实现多页面的数据共享功能
- Android自定义View实现炫酷进度条
- OpenSSL的VC编程 - MD5
- 详解AndroidStudio中代码重构菜单Refactor功能
- Android自定义View仿QQ运动步数效果
- Kotlin类型安全构建器的一次运用记录
- 两个surfaceView实现切换效果
- AndroidStudio4.0 New Class的坑(小结)
- Android日历控件的实现方法
- GetDiskFreeSpaceEx函数的一点处理
- Flutter轮播图效果的实现步骤