MySQL集群
 提升MySQL性能的方法:
  1、单机优化: 缓存优化,IO优化,网络优化,针对存储引擎优化等等。

  2、集群:

   数据分割:
    垂直切分:按功能、按业务对表进行分类,不同的分类对应的表放到不同的物理位置(不同的物理机器)。 论坛数据库中的用户表和帖子表耦合度低,可以对他们进行垂直切分。
  
 表1 | 表2 | 表3
 机器a1 | 机器a2 | 机器a3

    水平切分:在一个表当中,根据记录特点,划分到多个不同物理机器,划分之后,不同的物理机器的表,结构保持一直,只是存放记录不一样而已。水平切分可以根据id、日期、城市等等进行划分。
 
  
  记录1    /--- uid%2=0 物理机器b1 
  记录2
表2(业务) ... ---根据数据特征(uid取模) -->
  记录N-1
  记录N    \--- uid%2=1 物理机器b2

    

    分区:把数据分别存放不同的物理存储设备上,可以分散IO压力

   / 硬盘1
表2 ----> 物理机器b1 - 硬盘2
   \ 硬盘3


    读写分离:

 
   表2
   |读写分离,分担读的压力
 |------------------|
 r/w  r     r
 物理机器b1 物理机器c2 物理机器c3 

 


    分布式缓存:

   表2
   |读写分离,分担读的压力 <----- Memcached分布式缓存服务器
 |------------------|
 r/w  r     r
 物理机器b1 物理机器c2 物理机器c3

 


集群技术中,还有:
 MySQL NDB Cluster , 是一种share nothing的集群:
   数据节点,SQL节点,管理节点

 DRBD(网络raid)
   
  MySQL1 <--hb/rhcs--> MySQL2  <---只有一个数据库工作
    |     |
  Disk1 ---DRBD-----> Disk1

 


================================================================================


实现MySQL的复制
 双机热备,AB复制


 主服务器(Active)
  同时读写请求。打开线程,专门用户处理从服务器的连接。负责把二进制日志文件记录推送到从服务器。

 从服务器(Backup)
  只能接受读请求。有两个线程,一个叫IO_THREAD,专门用于主服务器,下载二进制日志记录。另外线程叫SQL_THREAD,专门用于把下载回来的记录应用一遍,这样就实现和主服务器的数据同步。 

 是一种异步的数据操作。

二进制日志文件 : 记录所有对数据库产生数据变更的操作
当前的日志名字mysqld-bin.000001
时间 pos 具体操作
01:05 170 insert .....
01:08 290 update ..... 《-----
01:22 341 create .....

日志文件已经写满,需要轮换
mysqld-bin.000002
1:58 110 delete ....
2:18 420 insert ....
2:22 580 update ....

 

常用的MySQL复制架构:


Master -----> Slave


Master  ----> Slave1
 ----> Slave2

   
Master ----- Slave1 -----> Slave2
       -----> Slave3


   
 -----> Slave1 -----> Slave12
Master
 -----> Slave2 -----> Slave23


Master <-----> Master

id name  id name
1 tom --> 1 tom
2 mary <-- 2 mary 
3 bean  3 jack  <---记录冲突


id name  id name
1 tom --> 2 tom
3 mary <-- 4 mary 
5 bean  6 jack 


===================================

步骤:
 准备:
  1、确保master打开了二进制日志记录功能。静态参数
  2、确定数据库服务器设定了server-id 。动态参数。

 实施:
  1、在master建立一个帐号,专门验证从服务器,允许服务器登录获得二进制日志记录信息。
  2、对master进行数据备份,备份的同时,确定好当前使用的二进制日志文件的相关状态。需要使用这些备份来搭建从服务器。
  备份的方法:
   冷备份:
   热备份:
    1)锁表,热拷贝。

    2)mysqldump
     对innodb影响不大,对非事务的存储引擎myisam等,就必须锁表。而且效率不高。
   
    3) 高端备份工具:对非事务的存储引擎myisam等,就必须锁表。
     Meb
     EtraBackup 

   选择不同的备份方法,会对搭建过程产生的影响也不一样。 

  3、使用备份数据搭建从服务器

  4、设定从服务器,让其如何去连接主服务器,从哪里开始同步数据

  5、从服务器启动复制线程。
  


例子1:实现简单MySQL AB复制


 Master -----> Slave


1、设定master的配置
[mysqld]
datadir=/data
socket=/var/lib/mysql/mysql.sock
user=mysql
log-bin=/data/mysql-binlog  《----
log-bin-index=/data/mysqll-binlog  《----
server-id=1  《----

[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid

 

2、建立帐号
允许slave同步所有数据
mysql> grant replication slave on *.* to slave@'1.1.1.%' identified by '123';


3、备份master的数据

# mysqldump --all-databases --lock-tables --single-transaction --master-data=2  -u root -p123  > /tmp/master.sql
 
--master-data=2  用于记录当前备份的时候,备份数据对应的数据库所在的状态。
  包括备份时候,master使用的二进制日志文件的名字和pos

 

 

4、使用备份数据搭建从服务器

1)设定好从服务配置文件,这是一个全新的从服务器
[mysqld]
datadir=/data
socket=/var/lib/mysql/mysql.sock
user=mysql

relay-log=mysqld-relay 《---
relay-log-index=mysqld-relay  《---
server-id=2

[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid


2)初始数据,启动

3)恢复备份数据
# mysql -u root  < /master.sql

mysql> flush privileges;

 

5、设定从服务关于复制的配置

从备份文件中提取到的信息
-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-binlog.000003', MASTER_LOG_POS=870;


slave> change master to
    -> master_host='1.1.1.128',
    -> master_user='slave',
    -> master_password='123',
    -> master_log_file='mysql-binlog.000003',
    -> master_log_pos=870;

 

mysql> start slave;

mysql> show slave status \G;
*************************** 1. row ***************************
             Slave_IO_State: Waiting for master to send event
                Master_Host: 1.1.1.128
                Master_User: slave
                Master_Port: 3306
              Connect_Retry: 60
            Master_Log_File: mysql-binlog.000003
        Read_Master_Log_Pos: 870
             Relay_Log_File: mysqld-relay.000002
              Relay_Log_Pos: 238
      Relay_Master_Log_File: mysql-binlog.000003
           Slave_IO_Running: Yes  <--- 一般都是连接失败,要么网络问题,要么帐号权限等
          Slave_SQL_Running: Yes  <--- 二进制记录执行成功,失败一般就是填写错误日志名字和pos


验证数据同步


例子2:在例子1的基础上再添加一个slave

 Master -----> Slave1 -----> Slave2

1、搭建master和Slave基本步骤一般


2、要对slave1的参数稍作修改

relay_log
中继日志,用于保存IO_THREAD从主服务器读取的二进制日志文件记录,然后SQL_THREAD去读取本地中继日志执行数据同步。

log-bin
二进制日志,如果是从服务器,他读取中继日志所进行数据同步,这些同步操作造成数据更新不是自己产生而且主服务器产生,默认这些更新操作不会记录在从服务器的二进制日志文件中。
 但是,如果该服务器它既是别的服务器从服务器,也是别的服务器的主服务器,那么就必须要这些不属于自己的更新操作也记录在二进制日志文件。

 


[mysqld]
datadir=/data
socket=/var/lib/mysql/mysql.sock
user=mysql

log-bin=/data/mysqld-bin  《---
log-bin-index=/data/mysqld-bin 《---

log-slave-updates  《---

relay-log=mysqld-relay 
relay-log-index=mysqld-relay 
server-id=2

[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
 
 
重启才能生效
# service mysqld restart


3、搭建slave2

注意:备份数据应该是来自slave1,然后用备份数据搭建slave2


例子3:搭建slave3实现延迟复制

 Master -----> Slave1 -----> Slave2
        ----->   Slave3 
 延迟备份:可以用于避免逻辑误操作。
 原理:slave3同样通过IO_THREAD去下载二进制日志记录,然后保存到中继日志,到了适当时间,才会使用SQL_THREAD读取中继日志执行相应的数据更新操作。

 实现方法:
  1、打补丁。
  2、自己写脚本实现
  3、第三方插件


需要实现延迟复制的slave3安装相应的插件

# rpm -ivh perl-TermReadKey-2.30-3.el5.rf.i386.rpm
# rpm -ivh maatkit-7119-1.noarch.rpm 《--插件


# mk-slave-delay --help

# mk-slave-delay --user=root --password=123 --socket=/var/lib/mysql/mysql.sock --delay=2m --interval=15s localhost

 --quiet 不会输出任何信息到终端
# mk-slave-delay --user=root --password=123 --socket=/var/lib/mysql/mysql.sock --delay=2m --interval=15s localhost --quiet  &

 建议一般延迟3-6个小时,--delay=6h


思考:
 如何在以上架构中实现数据库备份?有什么优点?
  选择末端中的一台slave进行备份,这里可以是slave2,备份的时候,就尽可能对上层应用带来很少的影响。

 如果出现故障,该如何处理?


如果处于master觉得服务器出故障,一般都是把它的从服务器指向新的上级服务器作为master
 slave1 出故障,可以让slave2指向master
 master 出故障,让slave1直接成为整个架构中master,然后把slave3指向slave1。
 整个角色迁移,难点和最容易出现故障就是二进制日志文件filename和pos判断。


例子4:模拟master出故障,让slave1成为master


一、
1、直接kill master服务器的mysql进程,模拟出想故障


2、登录slave1,查看状态

           Slave_IO_Running: No  《---master挂掉
          Slave_SQL_Running: Yes

3、让slave1直接成为master
mysql> stop slave;

告诉上层应用,以后写的请求都指向slave1

二、把slave3指向新master(slave1)
1、slave1上查看二进制日志文件的状态信息
mysql> show master status;
+-------------------+----------+--------------+------------------+
| File              | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+-------------------+----------+--------------+------------------+
| mysqld-bin.000001 |      837 |              |                  |
+-------------------+----------+--------------+------------------+

2、在slave3上修改master连接信息

暂时把延迟复制的插件也停止掉

mysql> stop slave;

mysql> change master to
    -> master_host='1.1.1.129',
    -> master_user='slave',
    -> master_password='123',
    -> master_log_file='mysqld-bin.000001',
    -> master_log_pos=837;

mysql> start slave;

 

三、如果原有故障的master服务器已经修复,需要重新上线。

怎么办?
 方法1:让它进行全新搭建,成为slave1的从服务器

 方法2:在保持原有的数据前提下,成为slave1的从服务器。
  chanage master ....
  start slave

mysql>change master to  master_host='1.1.1.129', master_user='slave', master_password='123', master_log_file='mysqld-bin.000001', master_log_pos=837;

注意:上线的时候,file和pos应该是当初master(node1节点)出故障的时候,和slave1(node2)的数据状态一样的。所以当master修复上线之后,change master所需要的file和pos就是那个时候的值。


  Slave1 -----> Slave2
          ----->   Slave3
   -----> master 


四、如果想让master重新成为整个架构中最顶级的master,恢复到最原始的架构


 Master -----> Slave1 -----> Slave2
        ----->   Slave3 

1、把slave1锁定,不能接受任何的数据写入
mysql> flush tables with read lock;

2、把master的slave进程停止,不再作slave1的从,还必须把master.info配置删除

mysql> show master status;
+---------------------+----------+--------------+------------------+
| File                | Position | Binlog_Do_DB | Binlog_Ignore_DB |
+---------------------+----------+--------------+------------------+
| mysql-binlog.000004 |       98 |              |                  |
+---------------------+----------+--------------+------------------+
3、修改slave1,让其重新成为master从服务器。

mysql> change master to
    -> master_host='1.1.1.128',
    -> master_user='slave',
    -> master_password='123',
    -> master_log_file='mysql-binlog.000004',
    -> master_log_pos=98;

mysql> start slave;

解锁
mysql> unlock tables;

4、相同的方法去修改slave3

=======================================================================

实现读写分离:

 方法1:直接在上层应用处理
 方法2:采用db_proxy数据代理服务器: mysql proxy

 

例子1:使用mysql_proxy实现mysql的读写分离负载均衡

  clients <--上层应用
  |  |  |
  DB Proxy 1.1.1.131
     |
 |----------|--------------|
 rw    ro    ro
 master    slave1 slave2
 1.1.1.128  1.1.1.129    1.1.1.130

 

1、安装lua语言支持包
lua 是一种解析型的编程语言,类似于php,shell,python,perl等
mysql proxy读取lua语言编写读写分离脚本,通过阿该脚本判断请求应该如何进行路由(调度)

# rpm -ivh lua-5.1.4-4.el5.i386.rpm

2、安装mysql proxy

# tar xvf mysql-proxy-0.7.2-linux-rhel5-x86-32bit.tar.gz
# mv mysql-proxy-0.7.2-linux-rhel5-x86-32bit /usr/local/mysql_proxy

 

3、执行
# cd /usr/local/mysql_proxy/
# ./sbin/mysql-proxy --help-all
# ./sbin/mysql-proxy --help-proxy


为了方便看实验效果,修改一下读写分离脚本
# vim /usr/local/mysql_proxy/share/doc/mysql-proxy/rw-splitting.lua

if not proxy.global.config.rwsplit then
        proxy.global.config.rwsplit = {
                min_idle_connections = 2,  <---把4改成2。
                max_idle_connections = 8,

                is_debug = false
        }
end

 

# ./sbin/mysql-proxy --admin-address=1.1.1.131:4041 --admin-lua-script=/usr/local/mysql_proxy/share/doc/mysql-proxy/admin-sql.lua  --admin-username=admin --admin-password=123 --log-file=/tmp/mysql-proxy.log --keepalive --proxy-address=1.1.1.131:4040 --proxy-backend-addresses=1.1.1.128:3306 --proxy-read-only-backend-addresses=1.1.1.129:3306 --proxy-read-only-backend-addresses=1.1.1.130:3306 --proxy-lua-script=/usr/local/mysql_proxy/share/doc/mysql-proxy/rw-splitting.lua

--proxy-backend-addresses 指定可读写的服务器
--proxy-read-only-backend-addresses 指定只读服务器,可以多个

--daemon 守护进程的形式启动


测试
# mysql -u bbs -p123 -h 1.1.1.131 -P 4040

mysql> select * from user.name;

如何设计验证读写分离的效果实验


===========================================

j2ee , haproxy , 云计算。