tokyo tyrant源码分析-主从复制实现

 

 

"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的一次连接,从而让数据的同步更及时。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值