Пару недель назад я написал пост, объясняющий, как создать причинный кластер Neo4j с использованием Kubernetes и… я хотел разработать, как имитировать сетевой раздел, который бы поставил лидера на сторону меньшинства и вынудил провести выборы.
Мы сделали это с помощью нашего внутреннего инструментария в AWS с помощью команды iptables, но, к сожалению, этого нет в моем контейнере, который имеет только утилиты, предоставляемые BusyBox .
К счастью, одним из них является команда маршрута, которая позволит нам достичь того же.
Напомним, у меня есть 3 Neo4j и работает:
|
1
2
3
4
5
|
$ kubectl get podsNAME READY STATUS RESTARTS AGEneo4j-0 1/1 Running 0 6hneo4j-1 1/1 Running 0 6hneo4j-2 1/1 Running 0 6h |
И мы можем проверить, доступна ли команда route :
|
1
2
|
$ kubectl exec neo4j-0 -- ls -alh /sbin/routelrwxrwxrwx 1 root root 12 Oct 18 18:58 /sbin/route -> /bin/busybox |
Давайте посмотрим, какую роль в настоящее время играет каждый сервер:
|
1
2
3
4
5
|
$ kubectl exec neo4j-0 -- bin/cypher-shell "CALL dbms.cluster.role()"role"FOLLOWER" Bye! |
|
1
2
3
4
5
|
$ kubectl exec neo4j-1 -- bin/cypher-shell "CALL dbms.cluster.role()"role"FOLLOWER" Bye! |
|
1
2
3
4
5
|
$ kubectl exec neo4j-2 -- bin/cypher-shell "CALL dbms.cluster.role()"role"LEADER" Bye! |
Немного в стороне: я могу вызвать cypher-shell без имени пользователя и пароля, потому что я отключил авторизацию, поместив в файл conf / neo4j.conf следующее :
|
1
|
dbms.connector.bolt.enabled=true |
Вернемся к разделу сети … нам нужно отделить neo4j-2 от двух других серверов, что мы можем сделать, выполнив следующие команды:
|
1
2
3
4
|
$ kubectl exec neo4j-2 -- route add -host neo4j-0.neo4j.default.svc.cluster.local reject && \ kubectl exec neo4j-2 -- route add -host neo4j-1.neo4j.default.svc.cluster.local reject && \ kubectl exec neo4j-0 -- route add -host neo4j-2.neo4j.default.svc.cluster.local reject && \ kubectl exec neo4j-1 -- route add -host neo4j-2.neo4j.default.svc.cluster.local reject |
Если мы посмотрим журналы neo4j-2, то увидим, что он вышел из строя после отключения от двух других серверов:
|
1
2
3
4
|
$ kubectl exec neo4j-2 -- cat logs/debug.log...2016-12-04 11:30:10.186+0000 INFO [o.n.c.c.c.RaftMachine] Moving to FOLLOWER state after not receiving heartbeat responses in this election timeout period. Heartbeats received: []... |
Кто стал лидером?
|
1
2
3
4
5
|
$ kubectl exec neo4j-0 -- bin/cypher-shell "CALL dbms.cluster.role()"role"LEADER" Bye! |
|
1
2
3
4
5
|
$ kubectl exec neo4j-1 -- bin/cypher-shell "CALL dbms.cluster.role()"role"FOLLOWER" Bye! |
|
1
2
3
4
5
|
$ kubectl exec neo4j-2 -- bin/cypher-shell "CALL dbms.cluster.role()"role"FOLLOWER" Bye! |
Похоже, neo4j-0! Давайте поместим некоторые данные в базу данных:
|
1
2
3
4
|
$ kubectl exec neo4j-0 -- bin/cypher-shell "CREATE (:Person {name: 'Mark'})"Added 1 nodes, Set 1 properties, Added 1 labels Bye! |
Давайте проверим, добрался ли этот узел до двух других серверов. Мы ожидаем, что он будет на neo4j-1, но не на neo4j-2:
|
1
2
3
4
5
|
$ kubectl exec neo4j-1 -- bin/cypher-shell "MATCH (p:Person) RETURN p"p(:Person {name: "Mark"}) Bye! |
|
1
2
3
4
|
$ kubectl exec neo4j-2 -- bin/cypher-shell "MATCH (p:Person) RETURN p" Bye! |
На neo4j-2 мы неоднократно будем видеть эти типы записей в журнале, поскольку время его ожидания срабатывает, но не получает никаких ответов на запросы голосования, которые оно отправляет:
|
1
2
3
4
5
|
$ kubectl exec neo4j-2 -- cat logs/debug.log...2016-12-04 11:32:56.735+0000 INFO [o.n.c.c.c.RaftMachine] Election timeout triggered2016-12-04 11:32:56.736+0000 INFO [o.n.c.c.c.RaftMachine] Election started with vote request: Vote.Request from MemberId{ca9b954c} {term=11521, candidate=MemberId{ca9b954c}, lastAppended=68, lastLogTerm=11467} and members: [MemberId{484178c4}, MemberId{0acdb8dd}, MemberId{ca9b954c}]... |
Мы можем увидеть эти запросы голосования, посмотрев raft-messages.log, который можно включить, установив следующее свойство в conf / neo4j.conf :
|
1
|
causal_clustering.raft_messages_log_enable=true |
|
01
02
03
04
05
06
07
08
09
10
11
|
$ kubectl exec neo4j-2 -- cat logs/raft-messages.log...11:33:42.101 -->MemberId{484178c4}: Request: Vote.Request from MemberId{ca9b954c} {term=11537, candidate=MemberId{ca9b954c}, lastAppended=68, lastLogTerm=11467}11:33:42.102 -->MemberId{0acdb8dd}: Request: Vote.Request from MemberId{ca9b954c} {term=11537, candidate=MemberId{ca9b954c}, lastAppended=68, lastLogTerm=11467} 11:33:45.432 -->MemberId{484178c4}: Request: Vote.Request from MemberId{ca9b954c} {term=11538, candidate=MemberId{ca9b954c}, lastAppended=68, lastLogTerm=11467}11:33:45.433 -->MemberId{0acdb8dd}: Request: Vote.Request from MemberId{ca9b954c} {term=11538, candidate=MemberId{ca9b954c}, lastAppended=68, lastLogTerm=11467} 11:33:48.362 -->MemberId{484178c4}: Request: Vote.Request from MemberId{ca9b954c} {term=11539, candidate=MemberId{ca9b954c}, lastAppended=68, lastLogTerm=11467}11:33:48.362 -->MemberId{0acdb8dd}: Request: Vote.Request from MemberId{ca9b954c} {term=11539, candidate=MemberId{ca9b954c}, lastAppended=68, lastLogTerm=11467}... |
Чтобы «вылечить» сетевой раздел, нам просто нужно удалить все команды, которые мы запускали ранее:
|
1
2
3
4
|
$ kubectl exec neo4j-2 -- route delete neo4j-0.neo4j.default.svc.cluster.local reject && \ kubectl exec neo4j-2 -- route delete neo4j-1.neo4j.default.svc.cluster.local reject && \ kubectl exec neo4j-0 -- route delete neo4j-2.neo4j.default.svc.cluster.local reject && \ kubectl exec neo4j-1 -- route delete neo4j-2.neo4j.default.svc.cluster.local reject |
Теперь давайте проверим, что у neo4j-2 теперь есть узел, который мы создали ранее:
|
1
2
3
4
5
|
$ kubectl exec neo4j-2 -- bin/cypher-shell "MATCH (p:Person) RETURN p"p(:Person {name: "Mark"}) Bye! |
На этом пока все!
| Ссылка: | Kubernetes: имитация сетевого раздела от нашего партнера по JCG Марка Нидхэма в блоге Марка Нидхэма . |