Browse Source

补充分区测试

ld
augurier 5 months ago
parent
commit
239cd694ab
2 changed files with 103 additions and 2 deletions
  1. +6
    -0
      README.md
  2. +97
    -2
      threadTest/network_partition_test.go

+ 6
- 0
README.md View File

@ -35,3 +35,9 @@ kill -9 杀死进程
通过新开进程的方式创建节点(参考test/common.go中executeNodeI函数 通过新开进程的方式创建节点(参考test/common.go中executeNodeI函数
如果通过线程创建,会出现重复注册rpc问题 如果通过线程创建,会出现重复注册rpc问题
## 客户端工作原理
客户端每次会随机连上集群中一个节点,此时有四种情况:
a 节点认为自己是leader,直接处理请求
b 节点认为自己是follower,且有知道的leader,返回leader的id。客户端再连接这个新的id,新节点重新分析四种情况。
c 节点认为自己是follower,但不知道leader是谁,返回空的id。客户端再随机连一个节点
d 连接超时,客户端重新随机连一个节点

+ 97
- 2
threadTest/network_partition_test.go View File

@ -33,7 +33,7 @@ func TestBasicConnectivity(t *testing.T) {
} }
} }
func TestElectionWithPartition(t *testing.T) {
func TestSingelPartition(t *testing.T) {
// 登记结点信息 // 登记结点信息
n := 3 n := 3
var peerIds []string var peerIds []string
@ -58,7 +58,7 @@ func TestElectionWithPartition(t *testing.T) {
} }
}() }()
time.Sleep(2 * time.Second) // 等待启动完毕
time.Sleep(time.Second) // 等待启动完毕
fmt.Println("开始分区模拟1") fmt.Println("开始分区模拟1")
var leaderNo int var leaderNo int
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
@ -147,4 +147,99 @@ func TestElectionWithPartition(t *testing.T) {
t.Errorf("日志数量不一致:" + strconv.Itoa(len(nodeCollections[i].Log))) t.Errorf("日志数量不一致:" + strconv.Itoa(len(nodeCollections[i].Log)))
} }
} }
}
func TestQuorumPartition(t *testing.T) {
// 登记结点信息
n := 5 // 奇数,模拟不超过半数节点分区
var peerIds []string
for i := 0; i < n; i++ {
peerIds = append(peerIds, strconv.Itoa(i + 1))
}
// 结点启动
var quitCollections []chan struct{}
var nodeCollections []*nodes.Node
threadTransport := nodes.NewThreadTransport()
for i := 0; i < n; i++ {
n, quitChan := ExecuteNodeI(strconv.Itoa(i + 1), false, peerIds, threadTransport)
quitCollections = append(quitCollections, quitChan)
nodeCollections = append(nodeCollections, n)
}
// 通知所有node结束
defer func(){
for _, quitChan := range quitCollections {
close(quitChan)
}
}()
time.Sleep(time.Second) // 等待启动完毕
fmt.Println("开始分区模拟1")
for i := 0; i < n / 2; i++ {
for j := n / 2; j < n; j++ {
threadTransport.SetConnectivity(nodeCollections[j].SelfId, nodeCollections[i].SelfId, false)
threadTransport.SetConnectivity(nodeCollections[i].SelfId, nodeCollections[j].SelfId, false)
}
}
time.Sleep(2 * time.Second)
leaderCnt := 0
for i := 0; i < n / 2; i++ {
if nodeCollections[i].State == nodes.Leader {
leaderCnt++
}
}
if leaderCnt != 0 {
t.Errorf("少数分区不应该产生leader")
}
for i := n / 2; i < n; i++ {
if nodeCollections[i].State == nodes.Leader {
leaderCnt++
}
}
if leaderCnt != 1 {
t.Errorf("多数分区应该产生一个leader")
}
// client启动
c := clientPkg.Client{PeerIds: peerIds, Transport: threadTransport}
var s clientPkg.Status
for i := 0; i < 5; i++ {
key := strconv.Itoa(i)
newlog := nodes.LogEntry{Key: key, Value: "hello"}
s = c.Write(nodes.LogEntryCall{LogE: newlog})
if s != clientPkg.Ok {
t.Errorf("write test fail")
}
}
time.Sleep(time.Second) // 等待写入完毕
// 恢复网络
for i := 0; i < n / 2; i++ {
for j := n / 2; j < n; j++ {
threadTransport.SetConnectivity(nodeCollections[j].SelfId, nodeCollections[i].SelfId, true)
threadTransport.SetConnectivity(nodeCollections[i].SelfId, nodeCollections[j].SelfId, true)
}
}
time.Sleep(1 * time.Second)
leaderCnt = 0
for j := 0; j < n; j++ {
if nodeCollections[j].State == nodes.Leader {
leaderCnt++
}
}
if leaderCnt != 1 {
t.Errorf("多leader产生")
}
// 日志一致性检查
for i := 0; i < n; i++ {
if len(nodeCollections[i].Log) != 5 {
t.Errorf("日志数量不一致:" + strconv.Itoa(len(nodeCollections[i].Log)))
}
}
} }

Loading…
Cancel
Save