一、背景

近期,新接手一项目,项目业务系统已上线,但是mysql未完成集群配置,但规划中有相关计划,遂计划在本文中回顾相关Mysql集群配置,也为项目中接下来的集群功能构建思路;

二、 集群架构选用

1、Mysql主从集群(最常用)

1)主从集群原理:

  Mysql主从集群主要是为了利用MySQL 的 Replication功能来实现,mysql的主从复制可以保证当服务器发生故障,可以切换到从服务器来确保业务服务的持续,另这种方式还可提高数据库服务器的稳定性,加快数据处理的效率,保护数据免受意外的损失,分离Mysql数据库的查询和更新操作,用从服务器上备份的数据保证来确保数据的安全性和稳定性。

  MySQL 的 Replication 是一个异步的复制过程,从一个 MySQL instace(我们称之为 Master)复制到另一个MySQL instance(我们称之 Slave)。

  在 Master 与 Slave 之间的实现整个复制过程主要由三个线程来完成,其中两个线程(Sql 线程和IO 线程)在 Slave 端,另外一个线程(IO 线程)在 Master 端(可查看本文下方的架构图)。下图是slaver上运行的IP和SQL线程:

mysql 集群方案 mysql集群原理详解_企业常用数据库集群配置


下图是master上的线程图,在top命令界面,按大H,开启查看线程模式:

mysql 集群方案 mysql集群原理详解_企业常用数据库集群配置_02


或者用ps -H -p 进程_PID:查看mysql进程的线程:

mysql 集群方案 mysql集群原理详解_主从复制_03


注意:执行这个主从复制之前,首先必须打开 Master 端的Binary Log(MySQL-bin.xxxxxx)功能,否则无法实现。因此,我们需找到MySQL安装文件夹修改my.cnf 文件,我们只要启动二进制日志log-bin :

vi /etc/my.cnf

在[mysqld]下面增加下面几行代码:

server-id=1 给数据库服务的唯一标识,一般为大家设置服务器Ip的末尾号来标识
 log-bin=master-bin
 log-bin-index=master-bin.index

============================================
【主从复制详细过程】:

============================================
1) Slave 上面的IO 线程连接上 Master,并请求从指定日志文件的指定位置(或者从最开始的日志)之后的日志内容。
2) Master 接收到来自 Slave 的 IO 线程的请求后,通过负责复制的 IO 线程根据请求信息读取指定日志指定位置之后的日志信息,返回给 Slave 端的 IO 线程。返回信息中除了日志所包含的信息之外,还包括本次返回的信息在 Master 端的 Binary Log 文件的名称以及在 BinaryLog 中的位置。

3)Slave 的 IO 线程接收到信息后,将接收到的日志内容依次写入到 Slave 端的RelayLog (中继日志文件)文件(MySQL-relay-bin.xxxxxx)的最末端,并将读取到的Master 端的bin-log 的文件名和位置记录到master-info 文件中,以便在下一次读取的时候能够清楚的告诉Master“我需要从某个bin-log 的哪个位置开始往后的日志内容,请发给我” 。
  
4)Slave 的 SQL 线程检测到 Relay Log 中新增加了内容后,会马上解析该 Log 文件中的内容成为在 Master 端真实执行时候的那些可执行的 Query 语句,并在自身执行这些 Query。

其实,整个复制过程在 Master 端和 Slave 端执行了同样的 Query,故两端的数据是完全一样的。

2)主从集群架构图

mysql 集群方案 mysql集群原理详解_多实例_04

3)集群构建

前景提要:搭建MySQL集群的时候,MySQL的版本尽量一致,大版本必须一致;主从复制,只能有一个主节点,可以用n多个从节点。

3.1)主节点配置(server)

sudo vim /etc/my.cnf

[mysqld]
  #bind-address=0.0.0.0
  .......
  ##下面为新增配置项
  server-id=1 给数据库服务的唯一标识,一般为大家设置服务器Ip的末尾号来标识
       log-bin=master-bin
       binlog-format=row
       log-bin-index=master-bin.index

重启MySQL服务:
/usr/local/mysql/support-files/mysql.server start
或sudo service mysql restart

【其他配置】:
master数据库上创建repl用户,赋予REPLICATION SLAVE权限,用来主从复制;

/usr/local/mysql/bin/mysql -uroot -p
mysql>create user repl;
mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'mysql_ip段或master_ip%' IDENTIFIED BY 'repl密码'; 
或GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
mysql> flush privileges;
mysql> select * from mysql.user where user='repl'\G  ##验证
mysql> SHOW MASTER STATUS;  ##重启mysql服务后,验证
mysql>exit;

mysql 集群方案 mysql集群原理详解_mysql集群_05


mysql 集群方案 mysql集群原理详解_多实例_06


如上图所示,Repl_salve_priv=Y,已开启复制;

mysql 集群方案 mysql集群原理详解_多实例_07


如上图所示,mysql_master二进制文件正常生成,服务正常。

3.2)Slaver从节点配置

关闭mysql服务器:/usr/local/mysql/support-files/mysql.server stop
sudo vim /etc/my.cnf

[mysqld]
 server-id=2
 relay-log-index=slave-relay-bin.index
 relay-log=slave-relay-bin

重启MySQL服务:
/usr/local/mysql/support-files/mysql.server start

3.3)连接Master
#/usr/local/mysql/bin/mysql -uroot -p
Enter password: 输入你的密码
mysql>stop slave;
mysql>change master to master_host='master_ip',##master所在服务器
master_port=3300,
master_user='repl',
master_password='上述配置的密码',
master_log_file='master-bin.000001',###上述查出的二进制文件名
master_log_pos=154;  ##对应master中查出的日志文件名和日子位置编号
mysql> start slave; 
mysql>show slave status;

mysql 集群方案 mysql集群原理详解_主从复制_08


注意:n个从节点时,slaver也都是相同的配置;

3.4)主从复制跳过一些命令执行的错误

在主从库维护中,有时候需要跳过某个无法执行的命令,需要在slave处于stop状态下,执行 set global sql_slave_skip_counter=N以跳过命令。常用的且不易用错的是N=1的情况,我们平时最常用的N=1的情况,都是跳过当前事务,去执行下一个事务。

【场景1】:

从库的复制出现中断,如主键冲突;对应的表或者库不存在;基于row复制时,操作的行不存在;常通过使用set global SQL_SLAVE_SKIP_COUNTER=n 来跳过导致复制错误的SQL。

MySQL从库从主库上复制binlog文件内容到本地执行。在binlog上命令以event的形式存在,并非一个命令对应一个event。官方解释set global sql_slave_skip_counter=N中,对于事务表,一个event group对应一个事务;对于非事务表,一个event group对应一条SQL语句。一个event group包含多个events。可以这样理解:主从复制,在slaver上的二进制日志实际上是作为一系列的事件组组成。每个事件组包含一系列的事件。对于事务表,一个事件组对应一个事务。对于非事务表,一个事件组对应一条单独的SQL语句。需要注意的是,一个单独的事务可能既包含事务表,也包含非事务表。当使用SET GLOBAL sql_slave_skip_counter跳过事件时,slave节点会处于事务组的中间,它会继续跳过一些事件直到它到达一个事务组的结束位置,然后slave节点会从下一个事件组开始执行。

以一个insert语句为例(引擎InnoDB、binglog_format=statement), 在binlog中实际上有==三个event,分别为begin\insert\commit ==。 命令类型都是Query_log_event。而
set globalsql_slave_skip_counter=N的意思,即为在start slave时,从当前位置起,跳过N个event。每跳过一个event,则N–,即N自减1。

1、若N=1且当前event为BEGIN, 则N不变,跳过当前event继续。
2、若N=1且当前event处于一个事务之内(BEGIN之后,COMMIT之前),则N不变,跳过当前event继续。
总之,其实上面两个策略合起来就是一句话,当N=1时,会连续跳过若干个event,直到当前所在的事务结束。当然如果N>1,则每跳过一个event都要N--.

命令举例:

假设某个Pos之后执行如下命令( 引擎InnoDB、binglog_format=statement):

insert into t values(x1);  ##start后从该位置执行,要想执行x4,需跳过4,5,6,7个都可以顺序完成x4的执行;---------->这一行相当于3个event;
begin;  -------------------->1  
insert into t values(x2); ------------------->1  ##从这里执行,N=4即可;
insert into t values(x3);   --------------------->1  ##从这里执行,N=5即可;
commit;                      ------------------------------>1  ###从此后执行,即进入下一个事务,N=6即
insert into t values(x4);  ------------>3个  ##从这里执行,N=7即可,即直接执行insert;N最小为1,减到1就按上面的默认策略理解。

你的从库stop在Pos上,假设你要跳过前面几个命令直接执行插入x4的操作,则你的N设置为 4或5或6或7均可。(X1语句为3个event);

上例中特别说明了在innodb引擎和statement模式下。其他情况区别如下:

1、若引擎为myisam(等不支持事务的引擎),且在statement下,则binlog中不会有begin和commit,每个命令都是一个event;

2、row模式的binlog里,一个insert语句实际上是两个event(Table_map_event和 Row_log_event), 计算时应与statement不同。

3、在row模式下,不论引擎是否支持事务,一个insert语句都会加上BEGIN和commit,也即变成4个event。

4、基于InnoDB引擎表的insert/delete/update操作都有显式样的BEGIN /COMMIT.

上面举的这个例子中,若为row模式,则要直接执行X4语句需要设置的N为 5~10均可。

set global sql_slave_skip_counte配置总结:

1、set global sql_slave_skip_counter=N中的N是指跳过N个event

   2、最好记的是N被设置为1时,效果是跳过下一个事务。

   3、跳过第N个event后,位置若刚好落在一个事务内部,则会跳过这整个事务

   4、一个insert/update/delete不一定只对应一个event,由引擎和日志格式决定

下图为配置set global sql_slave_skip_counter=1后的情况:

mysql 集群方案 mysql集群原理详解_多实例_09

3.5)测试

连接master 服务器,创建test 库,并在库中添加test 表,然后去slaver上登录数据库查看,是否数据同步/复制到slaver,知道看到同master相同的数据,即验证成功。

3.6)排错命令

1)show master status ; 查看master的状态, 获取二进制日志文件及位置
2)show slave status; 查看slave的状态,主从复制情况,sql和IO线程运行情况;
3)reset slave ; 重置slave状态,用于删除SLAVE数据库的relaylog日志文件,并重新启用新的relaylog文件.会忘记 主从关系,它删除master.info文件和relay-log.info 文件
4)start slave ; 启动slave 状态(开始监听msater的变化)
5)stop slave; 暂停slave状态;
6)set global sql_slave_skip_counter = n 跳过导致复制终止的n个事件,仅在slave线程没运行的状况下使用(注意这个命令,当报错时,可忽略,执行该命令,使用见上文)
7)查看Skip_Counter计数:

mysql> pager grep Skip_Counter;
PAGER set to 'grep Skip_Counter'
mysql> show slave status\G
                 Skip_Counter: 0
1 row in set (0.00 sec)

mysql>

8)sql_slave_skip_counter查询,默认为0:可执行show variables like ‘sql_slave%’;
9)暂时停止对bin-log日志的写入:set sql_log_bin=on/off

3.7)其他注意事项

mysql 5.6的复制引入了uuid的概念,各个复制结构中的server_uuid得保证不一样;可通过修改mysql/data/文件夹下的auto.cnf文件,修改里面的uuid值,保证各个db的uuid不一样;

show variables like '%server_uuid%';

2、MySQL多实例

1)概念说明

MySQL多实例就是在一台机器上开启多个不同的服务端口(如:3306,3307,3308),运行多个MySQL服务进程,通过不同的socket监听不同的服务端口来提供各自的服务。

【优缺点】:

1、有效利用服务器资源,当单个服务器资源有剩余时,可以充分利用剩余的资源提供更多的服务。从而多个实例公用一台服务器可大大节约服务器资源;
2、会资源互相抢占问题,当某个服务实例服务并发很高时或者开启慢查询时,会消耗更多的内存、CPU、磁盘IO资源,导致服务器上的其他实例提供服务的质量下降;

2)部署mysql多实例方式

1、用多个配置文件启动不同的进程来实现多实例。(逻辑简单,配置简单,需管理多个配置文件)
2、通过官方自带的mysqld_multi使用单独的配置文件来实现多实例。(不能实现单实例的个性化配置,但可集中管理,比较方便)

【注意事项】: 同一开发环境下需充分考虑和处理以下问题:
配置文件安装路径不能相同
数据库目录不能相同
启动脚本不能同名
端口不能相同
socket文件的生成路径不能相同

3)mysql多实例部署

3.1 mysqld_multi搭建

1、下载免编译二进制包:

下载地址:http://mirrors.sohu.com/mysql/下载对应版本的mysql

MySQL-server-6.0.11-0.glibc23.x86_64.rpm

mysql 集群方案 mysql集群原理详解_主从复制_10


2、解压和迁移

cd /usr/local/mysql
tar -zxvf mysql-5.7.17-linux-glibc2.5-x86_64.tar.gz
groupadd -g 27 mysql
useradd -u 27 -g mysql mysql

3、为多实例创建多个文件(这里创建3个实例3306,3307和3308):
mkdir -p /data/mysql/mysql_3306/data
mkdir -p /data/mysql/mysql_3306/log
mkdir -p /data/mysql/mysql_3306/tmp
mkdir -p /data/mysql/mysql_3307/data
mkdir -p /data/mysql/mysql_3307/log
mkdir -p /data/mysql/mysql_3307/tmp
mkdir -p /data/mysql/mysql_3308/data
mkdir -p /data/mysql/mysql_3308/log
mkdir -p /data/mysql/mysql_3308/tmp
随后赋予权限:
chown -R mysql:mysql /data/mysql/
chown -R mysql:mysql /usr/local/mysql/
4、添加环境变量
echo ‘export PATH=$PATH:/usr/local/mysql/bin’ >> /etc/profile
source /etc/profile
5、配置文件创建:
cp /usr/local/mysql/support-files/my-default.cnf /etc/my.cnf
完成后修改:my.cnf
vim /etc/my.cnf ##可参考以下文件配置

[client]

port=3306

socket=/tmp/mysql.sock

[mysqld_multi]

mysqld = /usr/local/mysql/bin/mysqld_safe

mysqladmin = /usr/local/mysql/bin/mysqladmin

log = /data/mysql/mysqld_multi.log

[mysqld]

basedir = /usr/local/mysql

sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES


#3306数据库

[mysqld3306]

mysqld=mysqld

mysqladmin=mysqladmin

datadir=/data/mysql/mysql_3306/data

port=3306

server_id=3306

socket=/tmp/mysql_3306.sock

log-output=file

slow_query_log = 1

long_query_time = 1

slow_query_log_file = /data/mysql/mysql_3306/log/slow.log

log-error = /data/mysql/mysql_3306/log/error.log

binlog_format = mixed

log-bin = /data/mysql/mysql_3306/log/mysql3306_bin

#3307数据库

[mysqld3307]

mysqld=mysqld

mysqladmin=mysqladmin

datadir=/data/mysql/mysql_3307/data

port=3307

server_id=3307

socket=/tmp/mysql_3307.sock

log-output=file

slow_query_log = 1

long_query_time = 1

slow_query_log_file = /data/mysql/mysql_3307/log/slow.log

log-error = /data/mysql/mysql_3307/log/error.log

binlog_format = mixed

log-bin = /data/mysql/mysql_3307/log/mysql3307_bin

#3308数据库

[mysqld3308]

mysqld=mysqld

mysqladmin=mysqladmin

datadir=/data/mysql/mysql_3308/data

port=3308

server_id=3308

socket=/tmp/mysql_3308.sock

log-output=file

slow_query_log = 1

long_query_time = 1

slow_query_log_file = /data/mysql/mysql_3308/log/slow.log

log-error = /data/mysql/mysql_3308/log/error.log

binlog_format = mixed

log-bin = /data/mysql/mysql_3308/log/mysql3308_bin

6、初始化数据库

1)#初始化3306数据库

/usr/local/mysql/scripts/mysql_install_db --basedir=/usr/local/mysql/ --datadir=/data/mysql/mysql_3306/data --defaults-file=/etc/my.cnf

2)#初始化3307数据库

/usr/local/mysql/scripts/mysql_install_db --basedir=/usr/local/mysql/ --datadir=/data/mysql/mysql_3307/data --defaults-file=/etc/my.cnf

3)#初始化3308数据库

/usr/local/mysql/scripts/mysql_install_db --basedir=/usr/local/mysql/ --datadir=/data/mysql/mysql_3308/data --defaults-file=/etc/my.cnf

7、验证数据库是否初始化成功
查看3306、3307、3308数据库,

cd /data/mysql/mysql_3306/data/
cd /data/mysql/mysql_3307/data/
cd /data/mysql/mysql_3308/data/

查看对应目录下是否有mysql相关文件
8、创建启动文件
cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysql
9、mysqld_multi进行多实例管理
启动全部实例:/usr/local/mysql/bin/mysqld_multi start

查看全部实例状态:/usr/local/mysql/bin/mysqld_multi report

启动单个实例:/usr/local/mysql/bin/mysqld_multi start 3306

停止单个实例:/usr/local/mysql/bin/mysqld_multi stop 3306

查看单个实例状态:/usr/local/mysql/bin/mysqld_multi report 3306
#启动全部实例:

/usr/local/mysql/bin/mysqld_multi start

/usr/local/mysql/bin/mysqld_multi report
验证:进入tmp目录,查看sock文件,是否有mysqld_3306.sock等sock文件;
10、修改密码
mysql的root用户初始密码是空,需要登录mysql进行修改密码, 登录任一mysql实例:

查看随机生成的mysql密码:grep “password” /var/log/mysqld.log

# mysql -S /tmp/mysql_3306.sock  ##应用3306通道,登录3306mysql实例
mysql>set password for root@'localhost'=password('xxxxxx');
mysql>flush privileges;

其他同理;
11、新建用户及授权
mysql>grant ALL PRIVILEGES on . to admin@‘%’ identified by ‘xxxxxx’;
mysql>flush privileges
至此,该种多实例构建完成。

3.2 多配置文件构建mysql多实例

重建多个MySQL示例配置文件,各实例启动时指定各自对应的配置文件,或写入启动脚本

3、Mysql常见高可用方案比较

3.1、主从复制优缺点

1)MySQL主从复制的复制方式:3种

  • 基于SQL语句的复制(statement-based replication,SBR

    SBR的优点:

    binlog文件较小
    binlog中包含了所有数据库更改信息,可以据此来审核数据库的安全等情况
    binlog可以用于实时的还原,而不仅仅用于复制
    主从版本可以不一样,从服务器版本可以比主服务器版本高

    SBR的缺点:

    不是所有的UPDATE语句都能被复制,尤其是包含不确定操作的时候;
    复制需要进行全表扫描(WHERE 语句中没有使用到索引)的 UPDATE 时,需要比 RBR 请求更多的行级锁;
    对于一些复杂的语句,在从服务器上的耗资源情况会更严重,而 RBR 模式下,只会对那个发生变化的记录产生影响;
    数据表必须几乎和主服务器保持一致才行,否则可能会导致复制出错;
    执行复杂语句如果出错的话,会消耗更多资源;
    \
  • 基于行的复制(row-based replication,RBR

    RBR的优点:

    任何情况都可以被复制,这对复制来说是最安全可靠的
    和其他大多数数据库系统的复制技术一样
    多数情况下,从服务器上的表如果有主键的话,复制就会快了很多;

    RBR 的缺点:

    binlog 大了很多
    复杂的回滚时 binlog 中会包含大量的数据
    主服务器上执行 UPDATE 语句时,所有发生变化的记录都会写到 binlog 中,而 SBR 只会写一次,这会导致频繁发生 binlog 的并发写问题
    无法从 binlog 中看到都复制了写什么语句
    \
  • 混合模式复制(mixed-based replication,MBR

    混合方式就是有mysql自动选择RBR方式和SBR方式,能够充分发挥两种方式的优点,一般情况下都使用该种方式实现主从复制;
    \
  • 全局事务标识符 GTID(Global Transaction Identifier,GTID

    mysql 5.6复制新特性下主从复制配置已支持基于GTID,这种方式能够大大提高主从复制的效率,减小主从复制的延时;

简单总结:

STATEMENT∶基于语句的复制。在服务器上执行sgl语句,在从服务器上执行同样的语句,mysgl默认采用基于语句的复制,执行效率高。
ROW∶ 基于行的复制。把改变的内容复制过去, 而不是把命令在从服务器上执行一遍。
MIXED∶混合类型的复制。黑默认采用基于语句的复制,一旦发现基于语句无法精确复制时,就会采用基于行的复制。

注意:相关经验表明使用row格式的binlog时,数据不一致问题更容易被发现。而使用mixed或者statement格式的binlog时,可能过了很久才发现数据不一致的问题;另主备切换的可用性优先策略会导致数据不一致。因此,大多数情况下,建议采用可靠性优先策略。

3.2、

4、mysql企业集群方案

mysql 集群方案 mysql集群原理详解_主从复制_11


上述架构可适用于中小型互联网的企业,WEB客户端(用户)读取数据库的时候读取dbproxy服务器。dbproxy服务器通过对SQL语句的判断来进行数据库的读写分离。读请求负载到从库,写请求写主库。图中,dbproxy是数据库集群的唯一出口,故也做了高可用的主备/双主方案;

其中,DBProxy是一个位于前端应用与后端MySQL数据库之间的中间件,它使得应用程序员无需再关心读写分离、分表等与MySQL相关的细节,可以专注于编写业务逻辑,同时使得DBA的运维工作对前端应用透明,上下线DB前端应用无感知。DBProxy支持分库分表,读写分离,它是数据库读写分离的常用软件,amoeba、mycat、cobar也很常用。这类软件不仅带有读写分离功能,还可以实现负载均衡以及后端节点的健康检查。这里主要简要介绍下DBproxy,其也应用最广。

DBProxy是由美团点评公司技术工程部DBA团队(北京)开发维护的一个基于MySQL协议的数据中间层。DBProxy在美团点评广泛应用,包括美团支付、酒店旅游、外卖、团购等产品线,公司内部对DBProxy的开发全面转到github上,开源和内部使用保持一致。目前只支持MySQL,版本有(Percona)5.5和5.6。

DBproxy的主要特性:

●读写分离
●负载均衡
●支持分表
●IP过滤
●sql语句黑名单
●DBA平滑下线DB
●从库流量配置
●动态加载配置项

部署参考手册:
https://github.com/Meituan-Dianping/DBProxy/blob/master/doc/QUICK_START.md

注意:主库要做双主高可用,实现主库挂掉另一个主库立刻接管。如果不做双主,从库接管主库的时候需要做状态迁移,会有延迟。

  • 读写分离场景:

    读写分离就是只在主服务器上写,只在从服务器上读。基本的原理是让主数据库处理事务性查询,而从数据库处理select查询。
    因为数据库的"写"(写10000条数据可能要3分钟)操作是比较耗时的。
    但是数据库的"读" (读10000条数据可能只要5秒钟)
    所以读写分离,解决的是,数据库的写入,景响了查询的效率。如果程序使用数据库较多时,而更新少,查询多的情况下会考虑使用。利用数据库主从同步,再通过读写分离可以分担数据库压力,提高性能。

mysql 集群方案 mysql集群原理详解_mysql 集群方案_12


读写分离基本的原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT香询操作。数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。

1)读写分离分常见的2两种方式∶

(1)基于程序代码内部实现

在代码中根据 select、insert,进行路由分类,这类方法也是目前生产环境应用最广泛的。
优点是性能较好,因为在程序代码中实现,不需要增加额外的设备为硬件开支;
缺点是需要开发人员来实现,运维人员无从下手。
但是并不是所有的应用都适合在程序代码中实现读写分离,像一些大型复杂的Java应用,如果在程序代码中实现读写分离对代码改动就较大。

(2)基于中间代理层实现

代理一般位于客户端和服务器之间, 代理服务器接到客户端请求后通过判断后转发到后端数据库, 有以下代表性程序。

①MySQL-Proxy。 MySQL-Proxy 为 MySOL开源项目, 通过其自带的 lua 脚本进行SOL 判断。
②Atlas。是由奇虎360的Web平台部基础架构团队开发维护的一个基于MySQL协议的数据中间层项目。它是在mysql-proxy0.8.2版本的基础上,对其进行了优化, 增加了一些新的功能特性。360内部使用Atlas运行的mysql业务,每天承载的读写请求数达几十亿条。支持事物以 及存储过程。
③Amoeba。 由陈思儒开发,作者曾就职于阿里巴巴。该程序由Jaya语言进行开发,阿里巴巴将其用于生产环境。但是它不支持事务和存储过程。

2)部署

//1、代理服务器部署,这里使用Amoeba
 
cd /opt/
cp jdk-6u14-linux-x64.bin /usr/local/
 
cd /usr/local/
chmod +x jdk-6u14-linux-x64.bin
./jdk-6u14-linux-x64.bin
 
mv jdk1.6.0_14/ /usr/local/jdk1.6
 
vim /etc/profile
## 末行添加下列配置
export JAVA_HOME=/usr/local/jdk1.6
export CLASSPATH=$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
export PATH=$JAVA_HOME/lib:$JAVA_HOME/jre/bin/:$PATH:$HOME/bin
export AMOEBA_HOME=/usr/local/amoeba
export PATH=$PATH:$AMOEBA_HOME/bin
 
source /etc/profile
java -version

## 安装 Amoeba软件
mkdir /usr/local/amoeba
#https://sourceforge.net/projects/amoeba/files/Amoeba%20for%20mysql/3.x/amoeba-mysql-3.0.4-BETA-distribution.zip
wget https://sourceforge.net/projects/amoeba/files/Amoeba%20for%20mysql/2.2.x/amoeba-mysql-binary-2.2.0.tar.gz
tar zxvf /opt/amoeba-mysql-binary-2.2.0.tar.gz -C /usr/local/amoeba/
chmod -R 755 /usr/local/amoeba/
/usr/local/amoeba/bin/amoeba   //显示:amoeba start|stop 说明安装成功

cd /usr/local/amoeba/conf/
 
cp amoeba.xml amoeba.xml.bak #备份配置文件
vim amoeba.xml
## 30行修改 ##
<property name="user">amoeba</property>
## 32行修改 ##
<property name="password">123456</property>
## 115行修改 ##
<property name="defaultPool">master</property>
## 117行去掉注释 ##
<property name="writePool">master</property>
<property name="readPool">slaves</property>
 
 
cp dbServers.xml dbServers.xml.bak
 
vim dbServers.xml #修改数据库配置文件
## 23行注释掉 ##
<!-- mysql schema
<property name="schema">test</property>
-->
## 26行修改 ##
<!-- mysql user -->
<property name="user">test</property>
## 28 - 30 行取消注释 ##
<property name="password">123456</property>
## 45行修改 ##
<dbServer name="master" parent="abstractServer">
## 48行修改主服务器id ##
<property name="ipAddress">192.168.80.10</property>
## 52行修改从服务器名slave1 ##
<dbServer name="slave1" parent="abstractServer">
## 55行修改为从服务器slave1的ip ##
<property name="ipAddress">192.168.80.20</property>
## 复制58行上面6行粘贴,设置从服务器2的名slave2和地址
<dbServer name="slave2" parent="abstractServer">
<property name="ipAddress">192.168.80.30</property>
## 65行修改 ##
<dbServer name="slaves" virtual="true">
## 71行修改 ##
<property name="poolNames">slave1,slave2</property>
 
/usr/local/amoeba/bin/amoeba start& 
netstat -anpt | grep java #查看是否开启了8066端口

5、MySQL双主复制+keepalived高可用

【环境】:

mysql-vip: 192.168…45.2
mysql-1:192.168.45.3
mysql-2:192.168.45.4

1、mysql1配置: vim /etc/my.cnf

[client]
port            = 3306
socket          = /tmp/mysql.sock

[mysqld]
port            = 3306
socket          = /tmp/mysql.sock
datadir         =/usr/local/mysql/var/
skip-locking
skip-name-resolve
key_buffer = 64M
max_allowed_packet = 64M
table_cache = 2048
sort_buffer_size = 4M
net_buffer_length = 256K
read_buffer_size = 10M
read_rnd_buffer_size = 10M
myisam_sort_buffer_size = 16M
interactive_timeout = 240
wait_timeout = 240
max_connections = 800
connect_timeout=30
open_files_limit=8192
query_cache_size = 1024M
thread_cache_size=16
thread_concurrency = 8
long_query_time = 1
log-slow-queries = slow.log

innodb_additional_mem_pool_size = 8M
innodb_buffer_pool_size = 32M
innodb_log_buffer_size=8M
innodb_log_file_size = 256M
innodb_log_files_in_group = 3
innodb_file_io_threads = 8
innodb_lock_wait_timeout= 50
innodb_thread_concurrency = 16
innodb_file_per_table

log_slave_updates
expire_logs_days=7
auto_increment_increment=2
auto_increment_offset=2
binlog_format=mixed
log-bin=mysql-bin
server-id       = 8   ###为服务器制定唯一ID

[mysqldump]
quick
max_allowed_packet = 16M

[mysql]
no-auto-rehash

[isamchk]
key_buffer = 20M
sort_buffer_size = 20M
read_buffer = 2M
write_buffer = 2M

[myisamchk]
key_buffer = 20M
sort_buffer_size = 20M
read_buffer = 2M
write_buffer = 2M

[mysqlhotcopy]    ###双主复制
interactive-timeout

设置mysql复制账号:

mysql>GRANT REPLICATION SLAVE ON . TO ‘repl’@‘192.168.45.3’ IDENTIFIED BY ‘repl_123’;
mysql>GRANT REPLICATION SLAVE ON . TO ‘repl’@‘192.168.45.4’ IDENTIFIED BY ‘repl_123’;

导出数据库:

#mysqldump -uroot -p --single-transaction --flush-logs --master-data=2 --all-databases > all.sql

2、MySQL2配置: vim /etc/my.cnf

[client]
port            = 3306
socket          = /tmp/mysql.sock

[mysqld]
port            = 3306
socket          = /tmp/mysql.sock
datadir			=/usr/local/mysql/var/ ##与主1一致
skip-locking
skip-name-resolve
key_buffer = 64M
max_allowed_packet = 64M
table_cache = 128
sort_buffer_size = 4M
net_buffer_length = 256K
read_buffer_size = 10M
read_rnd_buffer_size = 10M
myisam_sort_buffer_size = 64M
interactive_timeout = 240
wait_timeout = 240
max_connections = 800
connect_timeout=30
open_files_limit=8192
query_cache_size = 1024M
thread_cache_size=16
thread_concurrency = 8
long_query_time = 1
log-slow-queries = slow.log

innodb_additional_mem_pool_size = 8M
innodb_buffer_pool_size = 64M
innodb_log_buffer_size=8M
innodb_log_file_size = 256M
innodb_log_files_in_group = 3
innodb_file_io_threads = 8
innodb_lock_wait_timeout= 50
innodb_thread_concurrency = 16
innodb_file_per_table


log_slave_updates
expire_logs_days=7
auto_increment_increment=2
auto_increment_offset=1
binlog_format=mixed
log-bin=mysql-bin
server-id       = 9  ###为服务器制定唯一ID

[mysqldump]
quick
max_allowed_packet = 16M

[mysql]
no-auto-rehash

[isamchk]
key_buffer = 20M
sort_buffer_size = 20M
read_buffer = 2M
write_buffer = 2M

[myisamchk]
key_buffer = 20M
sort_buffer_size = 20M
read_buffer = 2M
write_buffer = 2M

[mysqlhotcopy]  ##双主复制
interactive-timeout

导入主库数据

#mysql -uroot -p < all.sql

设置同步

mysql> CHANGE MASTER TO MASTER_HOST=‘192.168.45.238’,MASTER_PORT=‘3306’,MASTER_USER=‘repl’,MASTER_PASSWORD=‘repl_123’,MASTER_LOG_FILE=‘mysql-bin.000007’,MASTER_LOG_POS=106;
 mysql> start slave; ##启动slaver复制

在MySQL1上执行相同的同步操作指令:

mysql>CHANGE MASTER TOMASTER_HOST=‘192.168.45.239’,MASTER_PORT=‘3306’,MASTER_USER=‘repl’,MASTER_PASSWORD=‘repl_123’,MASTER_LOG_FILE=‘mysql-bin.000008’,MASTER_LOG_POS=105020214;
 mysql>start slave;

实际就是上文主从数据库的变种,彼此互为主,彼此互为从。

3、配置keepalived

安装keepalived: 在2台mysql上分别安装并配置

wget http://www.keepalived.org/software/keepalived-1.2.2.tar.gz

mysql 集群方案 mysql集群原理详解_多实例_13


依据你的环境下载需要的版本,上图为比较新的版本。

编译安装:

tar zxvf keepalived-1.2.2.tar.gz
cd keepalived-1.2.2
./configure --prefix=/
make
make install

mysql1上keepalive的配置: vim /etc/keepalived/keepalived.conf

! Configuration File for keepalived
global_defs {
    router_id blue.com
}
vrrp_script check_run {
    script "/root/keepalived_check_mysql.sh"
    interval 5
}
vrrp_sync_group VG1 {
     group {
        VI_1
     }
}
vrrp_instance VI_1 {
     state MASTER
     interface eth0
     virtual_router_id 88
     priority 100
     advert_int 1
     nopreempt
     authentication {
         auth_type PASS
         auth_pass yuangang.net
     }
     track_script {
         check_run
     }
     virtual_ipaddress {                     ##虚拟ip配置,即VIP
         192.168.45.2
     }
}

编写mysql脚本用于检测验证mysql高可用:

vim test_keepalived

#!/bin/bash
MYSQL=/usr/local/mysql/bin/mysql
MYSQL_HOST=localhost
MYSQL_USER=root
MYSQL_PASSWORD=
CHECK_TIME=3
#mysql  is working MYSQL_OK is 1 , mysql down MYSQL_OK is 0
MYSQL_OK=1
function check_mysql_helth (){
$MYSQL -h $MYSQL_HOST -u $MYSQL_USER -e "show status;" >/dev/null 2>&1
if [ $? = 0 ] ;then
     MYSQL_OK=1
else
     MYSQL_OK=0
fi
     return $MYSQL_OK
}
while [ $CHECK_TIME -ne 0 ]
do
     let "CHECK_TIME -= 1"
     check_mysql_helth
if [ $MYSQL_OK = 1 ] ; then
     CHECK_TIME=0
     exit 0
fi

if [ $MYSQL_OK -eq 0 ] &&  [ $CHECK_TIME -eq 0 ]
then
     /etc/init.d/keepalived stop
exit 1
fi
sleep 1
done
#!/bin/bash
MYSQL=/usr/local/mysql/bin/mysql
MYSQL_HOST=localhost
MYSQL_USER=root
MYSQL_PASSWORD=
CHECK_TIME=3
#mysql  is working MYSQL_OK is 1 , mysql down MYSQL_OK is 0
MYSQL_OK=1
function check_mysql_helth (){
$MYSQL -h $MYSQL_HOST -u $MYSQL_USER -e "show status;" >/dev/null 2>&1
if [ $? = 0 ] ;then
     MYSQL_OK=1
else
     MYSQL_OK=0
fi
     return $MYSQL_OK
}
while [ $CHECK_TIME -ne 0 ]
do
     let "CHECK_TIME -= 1"
     check_mysql_helth
if [ $MYSQL_OK = 1 ] ; then
     CHECK_TIME=0
     exit 0
fi

if [ $MYSQL_OK -eq 0 ] &&  [ $CHECK_TIME -eq 0 ]
then
     /etc/init.d/keepalived stop
exit 1
fi
sleep 1
done
chmod 755  /root/keepalived_check_mysql.sh

mysql2上keepalive的配置: vim /etc/keepalived/keepalived.conf

! Configuration File for keepalived
global_defs {
    router_id blue.com
}
vrrp_script check_run {
    script "/root/keepalived_check_mysql.sh"
    interval 5
}
vrrp_sync_group VG1 {
     group {
       VI_1
     }
}
vrrp_instance VI_1 {
     state BACKUP
     interface eth0
     virtual_router_id 88
     priority 80
     advert_int 1
     authentication {
         auth_type PASS
         auth_pass blue.com
     }
     track_script {
         check_run
     }
     virtual_ipaddress {   ##虚拟ip配置一致
         192.168.45.2
     }
}

4、启动mysql和keepalived

启动 mysql-1上的keepalived mysql:

/etc/init.d/keepalived start
/etc/init.d/mysqld start

启动mysql-2上的keepalived mysql

/etc/init.d/keepalived start
/etc/init.d/mysqld start

5、验证:

关闭2台中其中1台上的mysql在另外一台机器上用vip连接mysql,连接正常同样的方法测试另一台机器。

6、Mysql+keepalived 双主单节点写

1、Mysql-master配置:单写/双写

vim /etc/my.cnf
#添加或修改内容如下
log_bin=mysql-bin
server-id=1
sync-binlog=1
#指定哪些库不同步,其他库默认都同步
binlog-ignore-db=information_schema
binlog-ignore-db=performance_schema
binlog-ignore-db=sys
#指定哪些库同步,不需要
#binlog-do-db=lanebin
#双主配置
relay_log=mysql-relay-bin
log_slave_updates=1
#双主单写可以不配置,双主双写要配置主键递增1,3,5,7,以下是双写配置
auto_increment_offset=1
auto_increment_increment=2
#授权
grant replication slave on *.* to 'root'@'%' identified by 'root';
grant all privileges on *.* to 'root'@'%' identified by 'root';
flush privileges

2、Mysql-slave

vim /etc/my.cnf
#添加或修改内容如下
log_bin=mysql-bin
server-id=12
sync-binlog=1
#指定哪些库不同步,其他库默认都同步
binlog-ignore-db=information_schema
binlog-ignore-db=performance_schema
binlog-ignore-db=sys
#指定哪些库同步,不需要
#binlog-do-db=lanebin
#双主配置
relay_log=mysql-relay-bin
log_slave_updates=1
##双主单写可以不配置,双主双写要配置主键递增2,4,6,8,双主
auto_increment_offset=2   #这里不一样
auto_increment_increment=2
#可以添加readonly:read_only=1;不会影响slave同步复制的功能
#
grant replication slave on *.* to 'root'@'%' identified by 'root';
grant all privileges on *.* to 'root'@'%' identified by 'root';
flush privileges

3)分别为 master1 和 master2 指定对方为主库

mysql> change master to master_host='172.16.10.4' ,master_port=3306,master_user='root',master_password='root',master_log_file='mysql-bin.000013',master_log_pos=884;
mysql> start slave;
#查看是否指定主库成功
mysql> show slave status \G;

mysql> change master to master_host='172.16.10.5' ,master_port=3306,master_user='root',master_password='root',master_log_file='mysql-bin.000004',master_log_pos=154;
mysql> start slave;
#查看是否指定主库成功
mysql> show slave status \G;

-----待整理