专职C++

不能停止的脚步

  C++博客 :: 首页 :: 联系 :: 聚合  :: 管理
  163 Posts :: 7 Stories :: 135 Comments :: 0 Trackbacks

常用链接

留言簿(28)

我参与的团队

搜索

  •  

最新评论

阅读排行榜

评论排行榜

来源:http://blog.csdn.net/pingnning/archive/2009/10/24/4724377.aspx
"tyrant分析-总体设计"中已经提到,slave起一个线程(do_slave)做主从复制,它和master建立tcp连接,发送请求命令和起始时间rts +1(上次的更新时间加1秒)给master,然后循环的从master那里接收一条条的记录,更新自己db、ulog和rts file。do_slave是以1秒为频率执行的。(实际是等待一次do_slave执行完毕后,再等待1秒,然后进入下一次的do_slave,依次循环。所以"以1秒为频率执行"的表达似乎并不准确。从下面可以看到一次do_slave有可能执行较长时间)

主从复制是一个主、从交互的过程。本节依次描述协议细节、slave细节、master细节。

------------

协议细节:

 do_slave(slave)          do_repl(master)

 -------------------

 | TTMAGICNUM|

 | TTCMDREPL  |

 | ts (+1)        |

 | sid         |   send and recv (with timeout)

 -------------------  ------------------------>

            -----------------

     send and cnd wait      | NOP      |

     <---------------------      -----------------

            -----------------------

            | TCULMAGICNUM |

            | rts         |

            | rsid         |

            | rsiz          |

       content send       | rsiz-content        |

     <---------------------      ------------------------

       next content send

     <---------------------

     ......

rsiz-content格式:

  MAGIC + cmd + ksize + vsize + key + value

其中:

 cmd: TTCMDPUT | TTCMDOUT | ...

 ksize,vsize分别是本条记录的key,value的长度;

 slave就根据cmd和key-value对对db进行相应操作。

master的ulog由一条条独立记录组成,每条记录有相同格式:

 MAGIC + ts + sid + size + content

其中:

 ts : 本条记录对应的时间戳。slave请求时会带上上次更新时间戳,master根据它们来判断需要传送哪些记录给slave;

 sid : server id. 唯一标识server。

 size : 后面"content"长度

 content格式即上面"rsiz-content"的格式,描述了一条key-value对以及对它做的操作命令。

--------------

do_slave流程:

 打开rts文件(默认为ttserver.rts),读取上次的rts(replication timestamp);

 和master建立socket连接(参数:-mhost,-mport),并设置socket选项:

  SO_RCVTIMEO、SO_SNDTIMEO - 发送、接收超时设置为0.25秒

  TCP_NODELAY - 禁止nagle算法

 发送REPL请求(详见协议细节);

 循环:

  用recv接收数据;

  解析接收数据,根据数据中指定的命令(TTCMDPUT、TTCMDOUT等)更新db和slave自己的ulog;

  用接收数据里的最新rts更新slave的rts文件;

 最后关闭连接

解释:

 1、slave不能因偶然的网络故障之类永远阻塞在send或recv中,这样的话更新就会永远停滞了。所以它要设置发送和接收的超时。如果超时,则这次do_slave失败,等待1秒后进行下一次。send | recv失败时,它并不会用新的rts(可能压根就没请求到它)去更新自己的rts文件,所以下次还是会用旧的rts去请求,所以不会因do_slave失败而导致slave数据不全。

 2、禁止nagle算法是因为有小数据的命令包的交互,不能拖延。

 3、请求只发送一次,但数据是一直循环接收的。循环失败的条件是:recv失败(或超时),收到SIGINT或SIGTERM,或是更新库失败或写文件失败等;

---------------

do_repl流程:

 根据slave的请求ts找到合适的ulog文件(文件名使用数字编号,依次递增),逻辑是:

  从编号最大的文件依次往编号小的文件:(编号越大,ulog内容越新,ts越大)

   打开文件查看它的第一条记录的ts,如果请求ts大于它,则该文件即为要找的ulog文件。

 循环。当对端连接未关闭且没收到SIGINT、SIGTERM信号时:

  发送NOP(测试对端连接是否关闭);

  pthread_cond_timedwait等待ulog更新信号,超时值为1秒;

  循环:

   一次读取一条日志记录;

   加上头部(MAGIC,rts,rsid,rsiz。见"协议细节");

   发送给slave。

   当上面读取日志失败或发送失败时,退出循环。

解释:

 1、ulog由一条条的记录组成,每条记录有相同格式: MAGIC + ts + sid + size + content

 2、因为ulog文件有大小上限,所以写满一个后会写下一个。按上面所说那样,文件名用数字编号,依次递增;

 3、找合适ulog文件的逻辑。因为是按内容从新到旧的顺序(也即ts从大到小的顺序)查看文件,所以最先找到的其中第一条记录ts小于slave所请求ts的那个文件就是合适的文件;(该文件里ts会随着一条条记录慢慢增加,直到大于等于请求ts,这时就到了slave需要的数据处);

 4、关于这两层循环的逻辑。内层循环一次发送一条记录,它是希望尽可能多地发送记录给slave,直到发送完所有记录(意外发送故障不考虑下)。退出到外层逻辑时希望这时又有ulog更新,能继续进行发送。这两层循环的目的都是希望能尽可能长地维持与slave的一次连接,从而让数据的同步更及时。

 

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/pingnning/archive/2009/10/24/4724377.aspx

posted on 2010-12-28 23:00 冬瓜 阅读(877) 评论(0)  编辑 收藏 引用 所属分类: 转贴

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理