mysql replication 实现原理

 mysql  mysql replication 实现原理已关闭评论
11月 052013
 

mysql replication 实现原理

一、replication 线程

Mysql 的Replication是一个异步的复制过程,从一个 mysql Instance(master)复制到另一个mysql Instance(slave)。在Master与Slave之间的整个复制过程主要由三个线程来完成,其中两个线程 SQL线程和IO线程在Slave端,另外一个线程 IO线程在Master端。

要实现Mysql Relication,首先必须打开Master的 Binary Log功能。因为整个复制功能实际上就是Slave从Master端获取二进制日志,然后在自己身上完全按照产生的顺序依次执行日志中所记录的各种操作。

MYSQL 复制的基本过程如下:

(1)Slave的IO线程连接上Master,并请求日志文件的指定位置(或者从最开始的日志)之后的日志内容;

(2)Master接收到来自Slave的IO线程请求后,负责复制的IO线程根据请求信息读取指定日志位置之后的日志信息,返回给Slave端的IO线程。返回信息中除了日志所包含的信息外,还包括本次返回的信息在Master端的Binary Log 文件的名称和位置;

(3)Slave的IO线程接收到信息后,将日志内容依次写入Slave端的Relay Log(中继日志)文件的最末端,并将读取到的Master端的Binary Log 文件名和位置记录到master-info文件中,以便在下次读取时能清楚地告诉master “我需要从某个bin-log文件的哪个位置开始完后的日志内容,发给我”;

(4)Slave的Sql线程检测到Relay Log中新内容后,会马上解析该Log文件中的内容,还原成在Master端真实执行的可执行Query语句,并执行这些Query。实际上就是在Master端和Salve端执行了同样的Query,所以两端的数据是完全一样的。

二、复制实现级别

(1)Row Level

Binary Log会记录成每一行数据被修改的形式,然后在Slave端再对相同的数据进行修改。

优点:在Row Level模式下,Binary Log可以不记录执行的Query语句的上下文相关信息,只需要记录哪一条记录被修改了,修改成什么样了。所以 Row Level的日志内容会非常清楚地记录下每一行数据修改的细节,非常容易理解。而且不会出现某些特定情况下的存储过程,或 function,以及 Trigger的调用和触发无法正确复制的问题。

缺点:在Row Level模式下,当所有的执行语句记录到Binary Log 中时,都将被记录成每条记录被修改的形式,这样就会产生大量的日志内容。比如有这样的一条 update语句:UPDATE group_message SET group_id = 1 WHERE group_id=2,执行后,日志记录的不是该语句而是产生影响的 表中的每条记录,即:如果group_message 中有 group_id=1 的记录100条,那么Binary Log中记录了这100条记录的变化情况。尤其执行 Alter Table 之类的语句时,产生的日志量更大的惊人。因为MYSQL对于Alter Table之类的DDL变更语句是重建整个表的所有数据,即表中每一条记录都要变动,那么该表中所有记录都要记录到日志中。

 

(2)Statement Level

每一条会修改数据的Query都会记录到Master的Binary Log中以及执行语句时上下文的信息。Slave 在复制的时候,SQL线程会解析成和原来 Master 端执行过的相同的 Query,并再次执行。

有点:首先解决了Row Level的缺点,不需要记录每一行记录的变化,减少了Binary Log 日志量,节约了IO成本,提高了性能。

缺点:由于记录的是执行语句,为了能让这些语句在Slave端也能正确执行,就需要记录每条语句在执行时的一些相关信息,即上下文信息。另外由于MYSQL发展比较快,很多新功能的加入,也使得mysql复制遇到不少挑战,复制时涉及的内容越复杂越容易出现bug。在修改数据时使用了默写特定的函数或功能后会出现问题。如 sleep()函数在默写版本中不能正确复制,在存储过程中使用 last_insert_id()函数,可能会使Slave 和Master得到不一致的ID,由于Row Level是基于每一行变化的所以不会出现这种情况。

(3) Mixed Level

在Mixed模式下,mysql会根据执行的每一条具体的Query语句来区分对待记录的日志形式,也就是在 Statement和Row之间选择一种。从5.1.8版本开始,Mysql提供了Statement Level 和 Row Level之外的第三种复制模式 Mixed Level

 

三、Replication 常用架构

(1) 常规复制架构 (Master – Slave)

主从复制架构,可以实现写读分离,只要Master端和 Slave端的压力不是很大,异步复制的延时一般都很少很少。尤其是自从Slave端的复制方式改成两个线程处理之后。

 

(2)Dual Master复制架构(Master – Master)

如果简单用常规复制架构 切换的话,就会造成原来Master端数据的不一致性,当原来的Master启动可以正常提供服务时,不得不通过反转Master – Slave 关系重新搭建Replication 环境,并以 原 Master 作为 Slave来对外提供服务。这将增加很多工作量。为了避免这个问题,可以搭建 Dual Master (双 Master),即两个Mysql Server互相将对方作为自己的Master,自己作为对方的Slave来进行复制。这样任何一方做的变更,都会通过复制应用到另一方数据库中。

为避免循环复制,Mysql的Binary Log中记录了当前Mysql的server-id ,mysql很容易判断某个变更是从哪一个mysql server最初产生的。另外如果不打开Slave的Binary Log选项(–log-slave-update)时,mysql根本就不会记录复制过程中产生的变更多 Binary Log中。

为了避免数据冲突一般指开启一端写服务,因为两端如果同时更新一条记录,会产生冲突 覆盖。

(3)级联复制架构(Master – Slave – Slave …)

在有些应用场景中,也许读写压力差别比较大,读压力特别大,一台Master 可能需要10台甚至更多的Slave才能支撑读的压力。

这时可利用MYSQL可以在 Slave端记录复制所产生的变更的 Binary Log 信息的功能,也就是打开 -log-slave-update 选项。然后通过二级复制来减少 Master端因为复制所带来的压力。也就是说,首先通过少数几台Mysql从Master来进行复制,这几台机器我们称为第一级Slave 集群,然后其他的Slave再通过第一级Slave集群来进行复制。从第一级Slave进行复制的Slave,称之为第二级Slave集群。如果有需要还可以继续往下增加更多层次的复制。

(4)Dual Master 与级联复制结合架构(Master-Master-Slaves)

级联复制在一定程度上确实解决了 Master因为所附属的Slave过多而成为瓶颈的问题,但并不能解决人工维护和出现异常需要切换时可能存在重新搭建 Replication的问题。

和Master – Salve – Salve 架构相比,区别只是将第一级的Slave集群换成了一台单独的Master,作为备用Master,然后再从这个Master复制到一个Slave集群,这样避免了主Master的写操作受到Slave集群的复制所带来的影响,同时主Master需要切换的时候也基本上不会出现重搭Replication的情况。但这个架构也有一个弊端,那就是备用的Master有可能成为瓶颈,如果后面Slave集群比较大的话,备用Master可能会因为过多的Slave IO线程请求而成为瓶颈。该备用Master不可供任何读服务时,瓶颈出现的可能性并不是很高

转自:http://www.cnblogs.com/shilijun/archive/2013/04/21/3034073.html

配置redis replication

 redis  配置redis replication已关闭评论
3月 062013
 

一、Redis的Replication:

这里首先需要说明的是,在Redis中配置Master-Slave模式真是太简单了。相信在阅读完这篇Blog之后你也可以轻松做到。这里我们还是先列出一些理论性的知识,后面给出实际操作的案例。
下面的列表清楚的解释了Redis Replication的特点和优势。
1). 同一个Master可以同步多个Slaves。
2). Slave同样可以接受其它Slaves的连接和同步请求,这样可以有效的分载Master的同步压力。因此我们可以将Redis的Replication架构视为图结构。
3). Master Server是以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步期间,客户端仍然可以提交查询或修改请求。
4). Slave Server同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据。
5). 为了分载Master的读操作压力,Slave服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成。即便如此,系统的伸缩性还是得到了很大的提高。
6). Master可以将数据保存操作交给Slaves完成,从而避免了在Master中要有独立的进程来完成此操作。

二、Replication的工作原理:

在Slave启动并连接到Master之后,它将主动发送一个SYNC命令。此后Master将启动后台存盘进程,同时收集所有接收到的用于修改数据集的命令,在后台进程执行完毕后,Master将传送整个数据库文件到Slave,以完成一次完全同步。而Slave服务器在接收到数据库文件数据之后将其存盘并加载到内存中。此后,Master继续将所有已经收集到的修改命令,和新的修改命令依次传送给Slaves,Slave将在本次执行这些数据修改命令,从而达到最终的数据同步。
如果Master和Slave之间的链接出现断连现象,Slave可以自动重连Master,但是在连接成功之后,一次完全同步将被自动执行。

三、如何配置Replication:

见如下步骤:
1). 同时启动两个Redis服务器,可以考虑在同一台机器上启动两个Redis服务器,分别监听不同的端口,如6379和6380。
2). 在Slave服务器上执行一下命令:
 /> redis-cli -p 6380   #这里我们假设Slave的端口号是6380
redis 127.0.0.1:6380> slaveof 127.0.0.1 6379 #我们假设Master和Slave在同一台主机,Master的端口为6379
OK
上面的方式只是保证了在执行slaveof命令之后,redis_6380成为了redis_6379的slave,一旦服务(redis_6380)重新启动之后,他们之间的复制关系将终止。
如果希望长期保证这两个服务器之间的Replication关系,可以在redis_6380的配置文件中做如下修改:
/> cd /etc/redis  #切换Redis服务器配置文件所在的目录。
/> ls
6379.conf  6380.conf
/> vi 6380.conf

    # slaveof <masterip> <masterport>
改为
    slaveof 127.0.0.1 6379
保存退出。
这样就可以保证Redis_6380服务程序在每次启动后都会主动建立与Redis_6379的Replication连接了。

四、应用示例:

这里我们假设Master-Slave已经建立。
    #启动master服务器。
[[email protected] redis]# redis-cli -p 6379
redis 127.0.0.1:6379>
    #情况Master当前数据库中的所有Keys。
redis 127.0.0.1:6379> flushdb
OK
    #在Master中创建新的Keys作为测试数据。
redis 127.0.0.1:6379> set mykey hello
OK
redis 127.0.0.1:6379> set mykey2 world
OK
    #查看Master中存在哪些Keys。
redis 127.0.0.1:6379> keys *
1) “mykey”
2) “mykey2”

    #启动slave服务器。
[[email protected] redis]# redis-cli -p 6380
    #查看Slave中的Keys是否和Master中一致,从结果看,他们是相等的。
redis 127.0.0.1:6380> keys *
1) “mykey”
2) “mykey2”

    #在Master中删除其中一个测试Key,并查看删除后的结果。
redis 127.0.0.1:6379> del mykey2
(integer) 1
redis 127.0.0.1:6379> keys *
1) “mykey”

    #在Slave中查看是否mykey2也已经在Slave中被删除。
redis 127.0.0.1:6380> keys *
1) “mykey”

在多台服务器上简单实现Redis的数据主从复制

 redis  在多台服务器上简单实现Redis的数据主从复制已关闭评论
3月 062013
 

Redis的主从复制功能非常强大,一个master可以拥有多个slave,而一个slave又可以拥有多个slave,如此下去,形成了强大的多级服务器集群架构。下面我演示下怎样在多台服务器上进行Redis数据主从复制。这里我假设有两台服务器,一台是Windows操作系统(局域网IP:192.168.3.82),一台是Linux操作系统(局域网IP:192.168.3.90),在两个操作系统都安装redis,Windows操作系统使用cygwin工具进行安装,命令为:

1
2
3
$ tar xzf redis-2.2.2.tar.gz
$ cd redis-2.2.2
$ make

可以通过”make test”命令判断是否安装成功。

 

这里我使用1个master以及2个slave(master在Windows下,一个slave在Windows下,一个slave在Linux下),基本流程是:

image

 

1. 在Windows服务器上创建两个目录,Demo1,Demo2,其中Demo1用来存放Master服务,Demo2用来存放Slave服务,

在Master服务中的配置文件修改:

1
bind 192.168.3.82

 

在Slave服务中的配置文件修改:

1
2
3
port 6381(服务端口号要分开)
bind 192.168.3.82
slaveof 192.168.3.82 6379 (设置master的Host以及Port)

 

2. 在Linux服务器上创建一个目录,Demo,Demo存放Slave服务,在服务中的配置文件修改:

1
2
bind 192.168.3.90
slaveof 192.168.3.82 6379(设置master的Host以及Port)

 

这样就完成了所有的配置。

 

3. 现在运行这3个服务,通过命令:

1
./redis-server redis.conf

来启动redis服务。

 

注意到,当我启动master,然后启动一个slave的时候,可以发现slave上:

image

会发送一个SYNC请求,从Master上面进行相应,而且它支持自动重连,即当master掉线的情况下,它会处于等待请求的状态。

而Master上:

image

能够接受Slave的应答,并且开始持久化操作,说明在Slave每次去连接Master的时候,都会去持久化磁盘。

 

4. 现在开始写一个客户端程序,使用到ServiceStack.Redis.dll的.NET组件:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using ServiceStack.Redis;
static void Main(string[] args)
{
    IRedisClientFactory factory = new RedisCacheClientFactory();
    IRedisClient client = factory.CreateRedisClient("192.168.3.82", 6379);
    client.Set<string>("username", "leepy");
    string username = client.Get<string>("username");
    client.Save();
    Console.WriteLine("username: {0}", username);
    Console.ReadLine();
}</string></string>

 

运行结果:

image

数据Set的时候,数据保存在内存中,当调用Save方法时候,将数据保存在磁盘中。

其中你会发现在3个服务目录中,都出现了dump.rdb,说明Master的文件都同步到Slave中去了。

image

image

用UE编辑器打开文件查看:

image
从Redis源码中,可以发现rdb文件采用的是lzf压缩算法进行实现,默认lzf压缩算法是开启的。

 

这样你可以通过其他的客户端程序或者Web平台去读取Slave磁盘数据库的数据,真正达到了读写分离的目的。


作者:Leepy
邮箱:sunleepy(AT)gmail.com