mysql主从延迟

1. MySQL数据库主从同步延迟原理。
要说延时原理,得从mysql的数据库主从复制原理提及,mysql的主从复制都是单线程的操做,
主 库对全部DDL和DML产生binlog,binlog是顺序写,因此效率很高,slave的Slave_IO_Running线程到主库取日志,效率很 比较高,下一步,问题来了,slave的Slave_SQL_Running线程将主库的DDL和DML操做在slave实施。DML和DDL的IO操做 是随即的,不是顺序的,成本高不少,还可能可slave上的其余查询产生lock争用,因为Slave_SQL_Running也是单线程的,因此一个 DDL卡主了,须要执行10分钟,那么全部以后的DDL会等待这个DDL执行完才会继续执行,这就致使了延时。有朋友会问:“主库上那个相同的DDL也需 要执行10分,为何slave会延时?”,答案是master能够并发,Slave_SQL_Running线程却不能够。

2. MySQL数据库主从同步延迟是怎么产生的。
当主库的TPS并发较高时,产生的DDL数量超过slave一个sql线程所能承受的范围,那么延时就产生了,固然还有就是可能与slave的大型query语句产生了锁等待。

3. MySQL数据库主从同步延迟解决方案。
丁奇的transefer是一个不错的方案,不过通常公司受限于对mysql的代码修改能力的限制和对mysql的掌控能力,仍是不太适合。
最 简单的减小slave同步延时的方案就是在架构上作优化,尽可能让主库的DDL快速执行。还有就是主库是写,对数据安全性较高,好比 sync_binlog=1,innodb_flush_log_at_trx_commit = 1 之类的设置,而slave则不须要这么高的数据安全,彻底能够讲sync_binlog设置为0或者关闭binlog,innodb_flushlog也 能够设置为0来提升sql的执行效率。另外就是使用比主库更好的硬件设备做为slave。
mysql-5.6.3已经支持了多线程的主从复制。原理和丁奇的相似,丁奇的是以表作多线程,oracle使用的是以数据库(schema)为单位作多线程,不一样的库可使用不一样的复制线程。

sync_binlog=1 o
     This makes MySQL synchronize the binary log's contents to disk each time it commits a transaction
     默认状况下,并非每次写入时都将binlog与硬盘同步。所以若是操做系统或机器(不只仅是MySQL服务器)崩溃,有可能binlog中最后的语句丢 失了。要想防止这种状况,你可使用sync_binlog全局变量(1是最安全的值,但也是最慢的),使binlog在每N次binlog写入后与硬盘 同步。即便sync_binlog设置为1,出现崩溃时,也有可能表内容和binlog内容之间存在不一致性。若是使用InnoDB表,MySQL服务器 处理COMMIT语句,它将整个事务写入binlog并将事务提交到InnoDB中。若是在两次操做之间出现崩溃,重启时,事务被InnoDB回滚,但仍 然存在binlog中。能够用--innodb-safe-binlog选项来增长InnoDB表内容和binlog之间的一致性。(注释:在MySQL 5.1中不须要--innodb-safe-binlog;因为引入了XA事务支持,该选项做废了),该选项能够提供更大程度的安全,使每一个事务的 binlog(sync_binlog =1)和(默认状况为真)InnoDB日志与硬盘同步,该选项的效果是崩溃后重启时,在滚回事务后,MySQL服务器从binlog剪切回滚的 InnoDB事务。这样能够确保binlog反馈InnoDB表的确切数据等,并使从服务器保持与主服务器保持同步(不接收 回滚的语句)。

innodb_flush_log_at_trx_commit (这个很管用)
抱 怨Innodb比MyISAM慢 100倍?那么你大概是忘了调整这个值。默认值1的意思是每一次事务提交或事务外的指令都须要把日志写入(flush)硬盘,这是很费时的。特别是使用电 池供电缓存(Battery backed up cache)时。设成2对于不少运用,特别是从MyISAM表转过来的是能够的,它的意思是不写入硬盘而是写入系统缓存。日志仍然会每秒flush到硬 盘,因此你通常不会丢失超过1-2秒的更新。设成0会更快一点,但安全方面比较差,即便MySQL挂了也可能会丢失事务的数据。而值2只会在整个操做系统 挂了时才可能丢数据。php

 

像Facebook、开心00一、人人网、优酷、豆瓣、淘宝等高流量、高并发的网站,单点数据库很难支撑得住,WEB2.0类型的网站中使用MySQL的 居多,要么用MySQL自带的MySQL NDB Cluster(MySQL5.0及以上版本支持MySQL NDB Cluster功能),或者用MySQL自带的分区功能(MySQL5.1及以上版本支持分区功能),我所知道的使用这两种方案的不多,通常使用主从复 制,再加上MySQL Proxy实现负载均衡、读写分离等功能,在使用主从复制的基础上,再使用垂直切分及水平切分;或者不使用主从复制,彻底使用垂直切分加上水平切分再加上 相似Memcached的系统也能够解决问题。html

1.优酷的经验
数据库采用水平扩展,主从复制,随着从数据库的增多,复制延迟愈来愈厉害,最终没法忍受。
最终仍是采用数据库的sharding,把一组用户相关的表和数据放到一组数据库上。
使用SSD来优化mysql的I/O,性能提高明显,每块16G,6块SSD作RAID。
数据库的类型选用MYISAM
数据库的拆分策略,先纵向按照业务或者模块拆分。对于一些特别大的表,再采用垂直拆分
根据用户进行分片,尽量不要跨篇查询。若是确实要跨片查询,能够考虑搜索的方案,先索引再搜索。
分布式的数据库方案太复杂,否掉。java

优酷使用的是数据库分片技术,而抛弃了因为数据量的愈来愈多致使复制延迟的问题。按照user_id进行分片,这样必须有一个全局的表来管理用户与shard的关系,根据user_id能够获得share_id,而后根据share_id去指定的分片查询指定的数据。mysql

假 如此表的表名为sharding_manager,若是网站的用户数太多,好比千万级的或甚至更大好比亿级的用户,此时此表也许也会成为一个瓶颈,由于查 询会很是频繁,全部的动态请求都要读此表,这时能够用其它的解决方案,好比用Memcached、Tokyo Cabinet、Berkeley DB或其它的性能更高的方案来解决。sql

具体怎么定位到哪台db服务器,定位到哪一个数据库,定位到哪一个shard(就是userN,msgN,videoN),优酷网的架构文档中说得不是很仔细,这里只能猜想一下了。数据库

根据优酷的架构图,一共有2台db服务器,每台db服务器有2个数据库,每一个数据库有3个shard,这样一共是2 * 2 * 3 = 12个shard。缓存

user_id 通常是自增型字段,用户注册的时候能够自动生成,而后看有几台db服务器,假若有m台db服务器,则用 user_id % m即可以分配一台db服务器(例如0对应100,1对应101,以此类推,字段mysql_server_ip的值肯定),假设每台服务器有n个数据库, 则用user_id % n能够定位到哪一个数据库(字段database_name的值肯定),假设每一个数据库有i个shard,则用user_id % i能够定位到哪一个shard(字段shard_id的值肯定),这样就能够进行具体的数据库操做了。安全

user_id share_id mysql_server_ip database_name
101      2           192.168.1.100   shard_db1
105      0           192.168.1.100   shard_db2
108      0           192.168.1.101   shard_db3(或shard_db1)
110      1           192.168.1.101   shard_db4(或shard_db2)服务器

如上述user_id为101的用户,链接数据库服务器192.168.1.100,使用其中的数据库为shard_db1,使用其中的表系列为user2,msg2,video2网络

若是上述的m,n,i发生变化,好比网站的用户不断增加,须要增长db服务器,此时则须要进行数据库迁移,关于迁移,参见这儿。

由于表位于不一样的数据库中,因此不一样的数据库中表名能够相同
server1(192.168.1.100)
shard_db1
user0
msg0
video0
user1
msg1
video1
...
userN
msgN
videoN
shard_db2
user0
msg0
video0
user1
msg1
video1
...
userN
msgN
videoN

由于表位于不一样的数据库服务器中,因此不一样的数据库服务器中的数据库名能够相同
server2(192.168.1.101)
shard_db3(这里也能够用shard_db1)
user0
msg0
video0
user1
msg1
video1
...
userN
msgN
videoN
shard_db4(这里也能够用shard_db2)
user0
msg0
video0
user1
msg1
video1
...
userN
msgN
videoN

2.豆瓣的经验
因为从主库到辅库的复制须要时间
更新主库后,下一个请求每每就是要读数据(更新数据后刷新页面)
从辅库读会致使cache里存放的是旧数据(不知道这个cache具体指的是什么,若是是Memcached的话,若是更新的数据的量很大,难道把全部更新过的数据都保存在Memcached里面吗?)
解决方法:更新数据库后,在预期可能会立刻用到的状况下,主动刷新缓存
不完美,but it works

豆瓣后来改成双MySQL Master+Slave说是能解决Replication Delay的问题,不知道是怎么解决的,具体不太清楚。

3.Facebook的经验

下面一段内容引用自www.dbanotes.net
大量的 MySQL + Memcached 服务器,布署简示:
California (主 Write/Read)............. Virginia (Read Only)
主 数据中心在 California ,远程中心在 Virginia 。这两个中心网络延迟就有 70ms,MySQL 数据复制延迟有的时候会达到 20ms. 若是要让只读的信息从 Virginia 端发起,Memcached 的 Cache 数据一致性就是个问题。

1 用户发起更新操做,改名 "Jason" 到 "Monkey" ;
2 主数据库写入 "Monkey",删除主端 Memcached 中的名字值,但Virginia 端 Memcached 不删;(这地方在 SQL 解析上做了一点手脚,把更新的操做"示意"给远程);
3 在 Virginia 有人查看该用户 Profile ;
4 在 Memcached 中找到键值,返回值 "Jason";
5 复制追上更新 Slave 数据库用户名字为 "Monkey",删除 Virginia Memcached 中的键值;
6 在 Virginia 有人查看该用户 Profile ;
7 Memcache 中没找到键值,因此从 Slave 中读取,而后获得正确的 "Monkey" 。
Via

从上面3能够看出,也仍然存在数据延迟的问题。同时master中数据库更新的时候不更新slave中的memcached,只是给slave发个通知,说数据已经改变了。

那是否是能够这样,当主服务器有数据更新时,当即更新从服务器中的Memcached中的数据,这样即便有延迟,但延迟的时间应该更短了,基本上能够忽略不计了。

4.Netlog的经验

对 于比较重要且必须实时的数据,好比用户刚换密码(密码写入 Master),而后用新密码登陆(从 Slaves 读取密码),会形成密码不一致,致使用户短期内登陆出错。因此在这种须要读取实时数据的时候最好从 Master 直接读取,避免 Slaves 数据滞后现象发生。还好,须要读取实时数据的时候很少,好比用户更改了邮件地址,就不必立刻读取,因此这种 Master-Slaves 架构在多数状况下仍是有效的。

 

 

 = = =

 

http://blogold.chinaunix.net/u3/116107/showart_2364757.html

 

 = = =

 

 

0_php_whc 17:28:20 http://koda.javaeye.com/blog/682547 0_php_whc 17:29:51 http://blog.csdn.net/MPU/archive/2010/06/23/5689225.aspx 0_php_whc 17:29:58 http://apps.hi.baidu.com/share/detail/17180907 0_php_whc 17:32:19 咱们如今采用的是 4.Netlog的经验对 于比较重要且必须实时的数据,好比用户刚换密码(密码写入 Master),而后用新密码登陆(从 Slaves 读取密码),会形成密码不一致,致使用户短期内登陆出错。因此在这种须要读取实时数据的时候最好从 Master 直接读取,避免 Slaves 数据滞后现象发生。还好,须要读取实时数据的时候很少,好比用户更改了邮件地址,就不必立刻读取,因此这种 Master-Slaves 架构在多数状况下仍是有效的。

相关文章
相关标签/搜索