How to replace the wheel of a car on the go? How to change the gear in the mechanism, so that everything does not break? And if at the same time the remaining gears are constantly falling off? And the mechanism is on fire? And you in hell?
In this talk, I will show how to update Java-microservices without unavailability for customers.
We will touch many different tools, such as HAProxy, Ansible, Vegeta, Mesos / Marathon, Ribbon / Eureka; there will be loads of configs and a bottomless ocean of pain of distributed systems, into which we will consistently sink.
20. А за окном…
‣ Сеть отваливается
‣ Серваки отваливаются
‣ Отвечают с задержкой
‣ Все такое неоднородное
‣ Толпа вредных админов
20
21. А за окном…
‣ Сеть отваливается
‣ Серваки отваливаются
‣ Отвечают с задержкой
‣ Все такое неоднородное
‣ Толпа вредных админов
21
22. А за окном…
‣ Сеть отваливается
‣ Серваки отваливаются
‣ Отвечают с задержкой
‣ Все такое неоднородное
‣ Толпа вредных админов
22
23. А за окном…
‣ Сеть отваливается
‣ Серваки отваливаются
‣ Отвечают с задержкой
‣ Все такое неоднородное
‣ Толпа вредных админов
23
?
?
?
24. Следствия
‣ В распределенных системах
отказы - обычное дело
‣ Нужно воспринимать это
как естественный атрибут системы
‣ Принять и осознанно проектировать систему
24
120. Here comes the pain
‣ Запросы на соединение приходят на случайный socket
‣ Старый процесс HAProxy тоже получает запросы на connect
‣ При большом RPS соединения кладутся в очередь
‣ Старый HAProxy может завершиться,
когда в очереди уже есть соединения :(
120
121. Here comes the pain
‣ Запросы на соединение приходят на случайный socket
‣ Старый процесс HAProxy тоже получает запросы на connect
‣ При большом RPS соединения кладутся в очередь
‣ Старый HAProxy может завершиться,
когда в очереди уже есть соединения :(
121
122. Here comes the pain
‣ Запросы на соединение приходят на случайный socket
‣ Старый процесс HAProxy тоже получает запросы на connect
‣ При большом RPS соединения кладутся в очередь
‣ Старый HAProxy может завершиться,
когда в очереди уже есть соединения :(
122
123. Here comes the pain
‣ Запросы на соединение приходят на случайный socket
‣ Старый процесс HAProxy тоже получает запросы на connect
‣ При большом RPS соединения кладутся в очередь
‣ Старый HAProxy может завершиться,
когда в очереди уже есть соединения :(
123
124. Решения?
‣ Ничего не делать
‣ Низкоуровневые заклятья для HAProxy
‣ Отказаться от HAProxy
124
125. Решения?
‣ Ничего не делать
‣ Низкоуровневые заклятья для HAProxy
‣ Отказаться от HAProxy
125
126. Решения?
‣ Ничего не делать
‣ Низкоуровневые заклятья для HAProxy
‣ Отказаться от HAProxy
126
127. Катимся к успеху
‣ In-place update
‣ Proxy
‣ Resource management
‣ Client side LB
127
140. Netflix Ribbon
140
public Server chooseServer(Object key) {
try {
return rule.choose(key);
} catch (Exception e) {
log.warn("LoadBalancer: Error choosing server for key {}”,
key, e);
return null;
}
}
141. Netflix Ribbon
141
public Server chooseServer(Object key) {
try {
return rule.choose(key);
} catch (Exception e) {
log.warn("LoadBalancer: Error choosing server for key {}”,
key, e);
return null;
}
}
142. Netflix Ribbon
142
public class RoundRobinRule extends AbstractLoadBalancerRule {
public Server choose(Object key) {
nextServerIndex = incrementAndGetModulo(serverCount);
return allServers.get(nextServerIndex);
}
}
143. Netflix Ribbon
143
private int incrementAndGetModulo(int modulo) {
for (;;) {
int current = nextServerCyclicCounter.get();
int next = (current + 1) % modulo;
if (nextServerCyclicCounter.compareAndSet(current, next))
return next;
}
}
144. Netflix Ribbon
144
private int incrementAndGetModulo(int modulo) {
for (;;) {
int current = nextServerCyclicCounter.get();
int next = (current + 1) % modulo;
if (nextServerCyclicCounter.compareAndSet(current, next))
return next;
}
}
145. Netflix Ribbon
145
private int incrementAndGetModulo(int modulo) {
for (;;) {
int current = nextServerCyclicCounter.get();
int next = (current + 1) % modulo;
if (nextServerCyclicCounter.compareAndSet(current, next))
return next;
}
}
152. ‣ Прямая коммуникация
‣ Нет точки отказа в виде
прокси-сервера
‣ Можно задавать правила
per-app
‣ Дополнительная логика на
клиенте
152
Client-side Server-side
‣ Прозрачно для
приложений
‣ Можно задавать
глобальные правила
‣ Дополнительные точки
отказа
vs
Load balancing
153. ‣ Прямая коммуникация
‣ Нет точки отказа в виде
прокси-сервера
‣ Можно задавать правила
per-app
‣ Дополнительная логика на
клиенте
153
Client-side Server-side
‣ Прозрачно для
приложений
‣ Можно задавать
глобальные правила
‣ Дополнительные точки
отказа
vs
Load balancing
154. Выдохнули
‣ In-place обновление - самое простое.
Но вызывает длинные окна недоступности.
‣ Недоступность можно обеспечить настройками прокси
и оркестрацией с healthcheck’ами
‣ Для large-scale оркестрации можно использовать
Mesos/Marathon + Marathon-LB
‣ Альтернатива проксям - Client-side Service Discovery
154
155. Выдохнули
‣ In-place обновление - самое простое.
Но вызывает длинные окна недоступности.
‣ Недоступность можно обеспечить настройками прокси
и оркестрацией с healthcheck’ами
‣ Для large-scale оркестрации можно использовать
Mesos/Marathon + Marathon-LB
‣ Альтернатива проксям - Client-side Service Discovery
155
156. Выдохнули
‣ In-place обновление - самое простое.
Но вызывает длинные окна недоступности.
‣ Недоступность можно обеспечить настройками прокси
и оркестрацией с healthcheck’ами
‣ Для large-scale оркестрации можно использовать
Mesos/Marathon + Marathon-LB
‣ Альтернатива проксям - Client-side Service Discovery
156
157. Выдохнули
‣ In-place обновление - самое простое.
Но вызывает длинные окна недоступности.
‣ Недоступность можно обеспечить настройками прокси
и оркестрацией с healthcheck’ами
‣ Для large-scale оркестрации можно использовать
Mesos/Marathon + Marathon-LB
‣ Альтернатива проксям - Client-side Service Discovery
157