1.psync2解释
以A ---> B ---> C ---> D为例说明一下psync2
B,C,D都是只读从库,无论怎么转化角色关系,半同步数据都一致。
B可写从库,C,D只读。那么B一旦写入数据,只要涉及到B的角色转换关系,半同步都会致使数据不一致。但复制链上的A,C,D仍然一致。
A ---> B ---> C ---> D
B写入数据,不会同步到C,D。B提升为主库,那么B作为可写从库时,写入的数据也不会同步到C,D(除非全同步)。
B开始为可写从库,之后提升为主库。提升为主库过程中,B强制C断开链接。接着C再半同步。B已经不是从库的角色,C无法同步B全部数据是不合理的。
所以说psync2这个协议只适合只读从库。
针对可写从库,作者做的设计就是只要可写,那么针对这个可写实例,做角色转换关系数据就必然不一致。他也明说了。
A ---> B ---> C
Even if B is writable, C will not see B writes and will instead have identical dataset as the master instance A.
这种设计是易于理解的。
2.修改方案
但是我们的场景,就是针对可写从库。要求可写从库数据必须同步到它的下一个复制链接。
假设B写入的数据,能同步到C。
A ---> B ---> C ---> D
B可写,写入的数据,会同步到C,D。
那么C,D,B互相转换角色时,半同步数据是一致的。那么C,D,B互相转换角色时,半同步数据是一致的。
A不一致,不一致的数据源来源不可控(C,D也可能可写)。
如果我们能接受如上设计。
只需要
1.对可读从库,保证遵守对可读从库,保证遵守psync2。
2.走清楚逻辑,避免改动对其他功能造成影响。
3.代码修改
1)从socket缓冲区中读取数据
readQueryFromClient(networking.c)
注释掉对pending_querybuf(缓存从库将主库发送过来的命令)的操作。
//else if (c->flags & CLIENT_MASTER) {
//c->pending_querybuf = sdscatlen(c->pending_querybuf,
// c->querybuf+qblen,nread);
//}
将以下代码修改为processInputBuffer(c);不对主库传播的命令做特殊处理。
让所有命令传播都经过replicationFeedSlaves。
/*if (!(c->flags & CLIENT_MASTER)) {
processInputBuffer(c);
} else {
size_t prev_offset = c->reploff;
processInputBuffer(c);
size_t applied = c->reploff - prev_offset;
if (applied) {
replicationFeedSlavesFromMasterStream(server.slaves,
c->pending_querybuf, applied);
sdsrange(c->pending_querybuf,applied,-1);
}
}*/
2.Redis通过processInputBuffer处理完命令之后,将命令传播到从库。
replicationFeedSlaves(replication.c)
注释掉对从库的操作
//if (server.masterhost != NULL) return; //当实例为从库,不传播到从库,直接返回。
这部分修改都是跟psync2相关,不影响redis其他部分的功能。合并起来比较容易。
4.方案影响
修改完成后:
对于可读从库,主库传播的命令正常通过replicationFeedSlaves传播到自己的slave。不破坏整个复制协议。
对于可写从库,主库传播的命令也正常通过replicationFeedSlaves传播到自己的slave,从库可写从客户端接受的命令传播到自己的slave。
网友评论