There is a problem of finding the best instance of a service in distributed systems with dynamic configuration. Nowadays, there are many products for the configuration storage and service discovery. It should be mentioned at least Netflix Eureka, Consul, etc or good old Zookeeper. These products can keep and give configuration, manage service instances lifecycle and some of them even can be as dynamic DNS service. But main question is not about what instance may be called at the certain time. It is about what instance is better for call? This means that smart load balancing top on service discovery is required. Spring Cloud project allows to integrate these products to your project and provides powerful solutions for typical problems, that make cloud native services developing easier. This talk will review the internal structure of SpringCloud implementation of Client-Side Service Discovery and Client Load Balancing patterns. It also will include specific details of concrete implementations with examples from official libraries and the author’s own library.
10. 10
Ещё одно решение
<providers>
<provider id="provider1"
url="socket://10.0.1.1:8080/?weight="42"/>
<provider id="provider2"
url="socket://10.0.1.2:8080/?weight="100"/>
</providers>
17. После набега
хипстеров
• Хост и порт, как правило,
заранее неизвестны
• Конфигурация меняется
постоянно, потому что
continuous delivery и прочий
DevOps
17
26. P = p5 = (0.999)5 ≈ 0.995
p – вероятность успеха вызова одного сервиса
26
Хотим как-то так
27. Service Discovery
• Какой инстанс мы можем
вызвать?
• Какой инстанс ЛУЧШЕ
подходит для вызова?
• Как мы можем увеличить
вероятность успеха одиночного
вызова?
27
69. 69
Рекомендуемый интерфейс
https://www.safaribooksonline.com/library/view/cloud-native-java/9781449374631/ch16.html
Spring Cloud provides the DiscoveryClient abstraction
to make it easy for clients to work with different types
of service registries.
Spring Cloud plugs the DiscoveryClient abstraction
into various parts of the stack, making its use almost
transparent.
The abstraction is simple enough that you
could adapt Spring Cloud to work with another service
registry if you’d like to. Conceptually,
the DiscoveryClient is read-only.
89. Вся правда о
DiscoveryClient
• Не используется для
клиентской балансировки
• Участвует в формировании
гиперссылок, в health-check
эндпоинтах и в получении
списка сервисов в реализации
edge-сервера
89
90. LoadBalancer
• Основан на Netflix Ribbon
• В принципе может быть
использован вне стека Spring
Cloud
• В общем случае не нуждается в
Service Registry
90
91. Service Service Service Service Service
STATE
FILTER
S2 S4
RULE
S1 S2 S3 S4 S5
S1 S2 S3 S4 S5
91
Client
call S4
92. Service Service Service Service Service
S2 S4
S1 S2 S3 S4 S5
S1 S2 S3 S4 S5
ServerList
92
Client
call S4
114. IPingStrategy SerialPingStrategy
int numCandidates = servers.length;
boolean[] results = new boolean[numCandidates];
for (int i = 0; i < numCandidates; i++) {
results[i] = false; /* Default answer is DEAD. */
if (ping != null) {
results[i] = ping.isAlive(servers[i]);
}
}
return results;
114
115. IPingStrategy SerialPingStrategy
int numCandidates = servers.length;
boolean[] results = new boolean[numCandidates];
for (int i = 0; i < numCandidates; i++) {
results[i] = false; /* Default answer is DEAD. */
if (ping != null) {
results[i] = ping.isAlive(servers[i]);
}
}
return results;
115
116. IPingStrategy SerialPingStrategy
int numCandidates = servers.length;
boolean[] results = new boolean[numCandidates];
for (int i = 0; i < numCandidates; i++) {
results[i] = false; /* Default answer is DEAD. */
if (ping != null) {
results[i] = ping.isAlive(servers[i]);
}
}
return results;
116
117. IPingStrategy SerialPingStrategy
int numCandidates = servers.length;
boolean[] results = new boolean[numCandidates];
for (int i = 0; i < numCandidates; i++) {
results[i] = false; /* Default answer is DEAD. */
if (ping != null) {
results[i] = ping.isAlive(servers[i]);
}
}
return results;
117
И что делать, если пинг слишком долгий?
144. upstream test-marathon-app {
server host1 weight=3;
server host2 weight=1;
server host3 weight=1;
}
Как правило вес предопределен
144
Типичный конфиг с весами
149. 149
Slow Instance Fast Instance
100 ms 10 ms5 000 requests
Round Robin Rule
Slow: 2500 and Fast: 2500
Average time: 70
150. 150
Slow Instance Fast Instance
100 ms 10 ms5 000 requests
Round Robin Rule
Slow: 2500 and Fast: 2500
Average time: 70
151. 151
Slow Instance Fast Instance
100 ms 10 ms5 000 requests
Round Robin Rule
Slow: 2500 and Fast: 2500
Average time: 70
Weighted Rule
Slow: 634 and Fast: 4366
Average time: 27
152. 152
Slow Instance Fast Instance
100 ms 10 ms1 000 requests
Round Robin Rule
Slow: 500 and Fast: 500
Average time: 70
Weighted Rule
?
?
153. 153
Slow Instance Fast Instance
100 ms 10 ms1 000 requests
Round Robin Rule
Slow: 500 and Fast: 500
Average time: 70
Weighted Rule
Slow: 500 and Fast: 500
Average time: 72
154. 154
Slow Instance Fast Instance
100 ms 10 ms1 000 requests
Round Robin Rule
Slow: 500 and Fast: 500
Average time: 70
Weighted Rule
Slow: 500 and Fast: 500
Average time: 72
160. Best Available Rule LoadBalancerStats
calculate
chosen -> activeConnections == min(activeConnections)
160
161. Best Available Rule LoadBalancerStats
calculate
chosen -> activeConnections == min(activeConnections)
161
Меньше активных соединений -> больше шансов на успех
162. 162
Slow Instance Fast Instance
100 ms 10 ms1 000 requests
Round Robin Rule
Slow: 500 and Fast: 500
Average time: 70
Weighted Rule
Slow: 500 and Fast: 500
Average time: 72
Best Available Rule
Slow: 152 and Fast: 847
Average time: 38
190. > ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
gif0: flags=8010<POINTOPOINT,MULTICAST> mtu 1280stf0: flags=0<> mtu 1280
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
en1: flags=963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX> mtu 1500
en2: flags=963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX> mtu 1500
p2p0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 2304
awdl0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1484
bridge0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
utun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1500
190
191. > ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
gif0: flags=8010<POINTOPOINT,MULTICAST> mtu 1280stf0: flags=0<> mtu 1280
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
en1: flags=963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX> mtu 1500
en2: flags=963<UP,BROADCAST,SMART,RUNNING,PROMISC,SIMPLEX> mtu 1500
p2p0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 2304
awdl0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1484
bridge0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
utun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1500
Low index
191
198. Выводы#1
• Облака, контейнеры,
динамическая привязка
ресурсов приводят к
необходимости решения
задачи обнаружения сервисов
• Но основная цель – это
предсказуемая и стабильная
работа всей системы в целом
198
199. Выводы#2
• В Spring Cloud-е много готовых
решений, но их использование
будет отличаться в
зависимости от выбранного
реестра сервисов
199
200. Выводы#3
• От нас многое прячут в недрах
конфигурации, и если
покопаться, то можно найти
интересные возможности
• Изучение базовых решений
(Netflix Ribbon. и т.д.) даст
возможность эффективнее
решать задачи
200
We fully changed technology stack for building this pilot small applications and discovered that they are not homogeneous. It contains UI-part, API, Database. We split our JSF frontend applications to NodeJS for client side and templating and Spring Boot for API. So, now we have several APIs that have small boundaries and business contexts that let the APIs do a small number of things, but do them well for your business tasks. For example, API for customer profile.