CQRS读写分离MySQL数据库如何部署至Linux

Posted C#郭小白

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CQRS读写分离MySQL数据库如何部署至Linux相关的知识,希望对你有一定的参考价值。

分库分表简单实现(FearlessGuo)

首先有一台可以使用的Linux服务器,可以自行购买,当然也可以白嫖。

有一款可以连接Linux的软件,我用的是putty

在Linux上下载docker镜像,类似应用商店。安装过程参阅下方链接

Linux安装Docker完整教程_docker安装_风随心飞飞的博客-CSDN博客

下载mysql镜像,查看版本

本次使用版本5.7

配置mysql的容器,每个容器就像是一台新的电脑,相互独立各不相同

实现dome:

--name后的内容可以修改

密码可以不为123456

结尾mysql为镜像名称,唯一可以只写name,不唯一也可以用id进行使用

这两段demo都可以创建容器,具体区别不清楚,多尝试一下,一个用不了就换一个。

1

docker run -itd --name mysql-test -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 mysql

2

docker run -p 3312:3306 --name mymysql -v $PWD/conf:/etc/mysql/conf.d -v $PWD/logs:/logs -v $PWD/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 -d mysql:5.7

Docker ps 查看运行镜像

Docker ps -a 查看所有镜像

测试mysql容器是否正常

如果连接失败了

参阅以下文章:

MySQL 异常: "Host \'xxx\' is not allowed to connect to this MySQL server"_mazaiting的博客-CSDN博客

下面我们配置数据库主从模式(可以当成读写分离)

  1. 我们专用的挂载好的容器(切记不要使用相同端口号,名字也不要相同)

//参数详解// -d守护进程// -p端口映射 -p 宿主机端口:容器端口// --privileged=true 应用容器 获取宿主机root权限// -v 绑定共享映射目录,-v 宿主机目录:容器目录

//主库

docker run -d -p 3322:3306 --privileged=true -v ~/docker_data/mysql-master/log:/var/log/mysql -v ~/docker_data/mysql-master/data:/var/lib/mysql -v ~/docker_data/mysql-master/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql-master mysql

//从库

docker run -d -p 3324:3306 --privileged=true -v ~/docker_data/mysql-slave/log:/var/log/mysql -v ~/docker_data/mysql-slave/data:/var/lib/mysql -v ~/docker_data/mysql-slave/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql-slave mysql

//可以多个从库

docker run -d -p 3325:3306 --privileged=true -v ~/docker_data/mysql-salve/log:/var/log/mysql -v ~/docker_data/mysql-salve/data:/var/lib/mysql -v ~/docker_data/mysql-salve/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql-salve mysql

下面我们需要配置Linux挂载文件夹里的文件

这里主库和从库的都已经备注好了

//**主库配置** 这里在宿主机更新配置文件后,容器也会同步更新//在刚刚共享映射的宿主机conf目录新建my.cnf 写入以下内容//我的目录是:/docker_data/mysql-master/conf/my.cnf teps:不需要复制这段话

[mysqld]

## 设置server_id 同一局域网中需要唯一

server_id=101

## 指定不需要同步的数据库名称

binlog-ignore-db=mysql

## 开启二进制日志功能

log-bin=mall-mysql-bin

## 设置二进制日志使用内存大小(事务)

binlog_cache_size=1M

## 设置使用的二进制日志格式(mixed,stateement,row)

binlog_format=mixed

## 二进制日志过期清理时间 默认值为0 表示不自动清理

expire_logs_days=7

## 跳过主从复制值遇到的所有错误或指定类型的错误,避免slave端复制中断## 如:1062错误是指一些主键重复 1032错误是因为主从数据库数据不一致

slave_skip_errors=1062

//**从库配置** 这里在宿主机更新配置文件后,容器也会同步更新//在刚刚共享映射的宿主机conf目录新建my.cnf 写入以下内容//我的目录是:/docker_data/mysql-slave/conf/my.cnf teps:不需要复制这段话

[mysqld]

## 设置server_id 同一局域网中需要唯一

server_id=102

## 指定不需要同步的数据库名称

binlog-ignore-db=mysql

## 开启二进制日志功能

log-bin=mall-mysql-slave1-bin

## 设置二进制日志使用内存大小(事务)

binlog_cache_size=1M

## 设置使用的二进制日志格式(mixed,stateement,row)

binlog_format=mixed

## 二进制日志过期清理时间 默认值为0 表示不自动清理

expire_logs_days=7

## 跳过主从复制值遇到的所有错误或指定类型的错误,避免slave端复制中断## 如:1062错误是指一些主键重复 1032错误是因为主从数据库数据不一致

slave_skip_errors=1062

## relay_log配置中继日志

relay_log=mall-mysql-relay-bin

## log_slave_updates表示slave将复制事件写进自己的二进制日志中

log_slave_updates=1

## slave设置为只读(具有super权限的用户除外)

read_only=1

如多多个从库变一下server_id就可以了只要不重复就行。想的话可以多设置几个小弟,搞两个给你们演示一下。

这是一个事例,其他的照着写就行。

下面一步一步进入主库(对主库创建slave用户)成功以后可查看是否创建了slave

Exit退出容器,去从库容器中进行配置

如果没报错的话会出来这样一个会话框

我们可以看见这两个状态是关闭的。

可能运行会有报错,empty,没关系这是我们少写了一段话,加上就行。

change master to master_host=\'47.97.19.23\', master_user=\'slave\', master_password=\'123456\', master_port=3322, master_log_file=\'mall-mysql-bin.000001\', master_log_pos=371, master_connect_retry=30;

这边需要最长的dome很贴心的放到这里了。切记一行代码,不能换行!!!!

当然如果直接复制粘贴的话,肯定报错。

需要修改一下port,为你主服务器的端口

还有其他的东西,自己看看去。

//开启主从复制

Start slave;

//查询从库状态

Show slave status \\G;

此处的状态已经为yes了说明我们已经配置成功了

这时候你的数据库就不是一个了,主库后面跟俩小弟,非常哇塞。

在主mysql里创建test数据库两个小弟也就有了

浅析CQRS的应用部署

 

CQRS,中文翻译命令和查询职责分离,它是一种架构,不仅可以从数据库层面实现读写分离,在代码层面上也是推荐读写分离的。在接口上可以更为简单

 

 

 

命令端定义

 

ICommandResult Execute(ICommand command)

 

查询端定义

 

IQueryResult Fetch(IQuery query)

 

 

 

它的好处是CQ每端对外只有一个接口,职责单一。带来的不便就是要定义好多命令(Command)和查询(Query)对象。但相比定义好多个接口个人觉得还是这样的方式更好。

 

CQRS不是一个特别炫丽的架构,我觉得他更多的是为了解决数据显示的复杂性。在实际项目中,往往是要查询的数据非常复杂和多样性(也许你并不认同),这样就可以针对查询定义相对需要的ReadModel,也可以设计多个有针对性的读库。

 

 

 

当我们的应用程序开发完之后就需要发布部署了,在部署之前你的应用程序需要有个宿主可以对外提供服务,它可以是WebService,Wcf,WebApi等等。

 

 

 

单机

 

 

 

单机是一个最简单的部署方式,优点是维护和部署起来很方便, 缺点是一旦宕机你的整个服务将不可用,处理能力有限,更新应用程序可能要停止服务。

 

 

 

集群

 

最简单的方式是部署多个单机,利用DNS轮询就可以实现简单的负载均衡,这种方案的缺点就是存在会话丢失,这是因为上一次的会话是在服务器1上,可能下一次的会话DNS就会将域名指向服务器2上,可以采用Cookie或者其他方案解决这一问题。还有就是这一集群方式在处理并发上难度较大,当然也可以采用乐观锁和数据库的悲观锁机制,不过这会带来性能问题。

 

 

 

 

 

 

上图只是对单机集群的一种扩展,Connection Manager负责管理与客户端的连接及请求,然后将具体的命令和查询转发到具体的Server,以达到负载均衡的目的,同时它可以将处理相同命令的请求路由到同一个服务器上,可以初步解决并发问题。这种方案也有点类似ngixn,缺点就是带宽压力较大

 

 

 

分布式

 

 

上图的部署方式将命令和查询服务严格区分开来,利用消息队列达到流量削锋、应用解藕和异步处理的目的。命令服务接收到命令后将其发送到Kafka,将相同类型的命令发送到同一topic中,再根据Key分发到不同的partition上,利用Kafka的Rebalance动态添加消费服务,这样的话就可以当请求过多时增加服务,闲时减少服务,非常灵活。

 

个人觉得这样的部署有类似微服务,在此基础上还可以分离出ValidationService和AuthenticationService等,如CommandService接收到命令后通过验证服务后再发送到Kafka中,同时也是将软件层面的AOP替换成服务层面,每个CommandConsumer像是一个黑盒,外部无法访问。

 

简单的示例可以参考 https://github.com/imyounghan/umizoo/tree/master/src/Samples

 

 

 

 

 

上图是对图2和图3的一个整合,利用了各自的优点。还有一种方案就是Connection Manager提供给客户端一个可用的CommandService或QueryService与客户端进行直连,这样可以避免所有的请求都要经过Connection Manager,减轻Connection Manager的带宽压力,可以参照P2P的思路。

 

 

 

采用了分布式后会导致服务增多,问题也会增多,管理起来也会变得复杂,可以借助Zookeeper来管理监控这些服务。总之分布式情况下要考虑的问题会有很多,本文也无逐一续清,需要掌握的知识点也较多。

 

以上是关于CQRS读写分离MySQL数据库如何部署至Linux的主要内容,如果未能解决你的问题,请参考以下文章

从读写分离到CQRS,张大胖是如何解决性能问题的?

CQRS不等同于读写分离

从读写分离到 CQRS,张大胖是如何解决性能问题的?

数据库,读写分离到CQRS

DDD CQRS架构和传统架构的优缺点比较

.NET CQRS-一种读写分离的数据处理模式