Пару недель назад я написал пост, объясняющий, как создать причинный кластер Neo4j с использованием Kubernetes и… я хотел разработать, как имитировать сетевой раздел, который бы поставил лидера на сторону меньшинства и вынудил провести выборы.
Мы сделали это с помощью нашего внутреннего инструментария в AWS с помощью команды iptables, но, к сожалению, этого нет в моем контейнере, который имеет только утилиты, предоставляемые BusyBox .
К счастью, одним из них является команда маршрута, которая позволит нам достичь того же.
Напомним, у меня есть 3 Neo4j и работает:
1
2
3
4
5
|
$ kubectl get pods NAME READY STATUS RESTARTS AGE neo4j-0 1 /1 Running 0 6h neo4j-1 1 /1 Running 0 6h neo4j-2 1 /1 Running 0 6h |
И мы можем проверить, доступна ли команда route :
1
2
|
$ kubectl exec neo4j-0 -- ls -alh /sbin/route lrwxrwxrwx 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 triggered 2016 - 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 Марка Нидхэма в блоге Марка Нидхэма . |