Skip to content

Commit b587e77

Browse files
committed
hw2
1 parent 958ffc9 commit b587e77

15 files changed

+720
-6
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,38 @@
1+
local threads = {}
2+
3+
function setup(thread)
4+
table.insert(threads, thread)
5+
end
6+
7+
function init(args)
8+
count_404 = 0
9+
count_503 = 0
10+
end
11+
112
function request()
2-
key = math.random(1000000)
13+
key = math.random(1750000)
314

415
return wrk.format("GET", "/v0/entity?id=k" .. key)
516
end
17+
18+
function response(status, headers, body)
19+
local nstatus = tonumber(status)
20+
if nstatus == 404 then count_404 = count_404 + 1
21+
elseif nstatus == 503 then count_503 = count_503 + 1
22+
end
23+
end
24+
25+
function done(summary, latency, requests)
26+
total_404 = 0
27+
total_503 = 0
28+
29+
for index, thread in ipairs(threads) do
30+
total_404 = total_404 + thread:get("count_404")
31+
total_503 = total_503 + thread:get("count_503")
32+
end
33+
34+
print("------------------------------\n")
35+
local msg_status = "HTTP Status %s Count: %d"
36+
print(msg_status:format("404", total_404))
37+
print(msg_status:format("503", total_503))
38+
end

src/main/java/ru/vk/itmo/test/kovalevigor/reports/scripts/lua/put_request.lua

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
function request()
2-
key = math.random(1000000)
2+
key = math.random(1750000)
33
value = ""
44
for i = 1, math.random(1, 100) do
55
value = value .. math.random(1, 100000)

src/main/java/ru/vk/itmo/test/kovalevigor/reports/scripts/sh/base.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
NAME=$(date +"%s")
33
JFR="../../info-$NAME.jfr"
44
PREFIX="../../html/stage2"
5-
(wrk2 -c 64 -t 1 -L -d $1 -R $2 -s "../lua/$3.lua" http://localhost:8080 > "${PREFIX}/${NAME}_wrk.txt") &
5+
(wrk2 -c 128 -t 8 -L -d $1 -R $2 -s "../lua/$3.lua" http://localhost:8080 > "${PREFIX}/${NAME}_wrk.txt") &
66
./ap/bin/asprof -t -e cpu,alloc,lock -d $1 -f $JFR MainServer
77

88
wait
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
## Факты
2+
3+
Была обновлена система с Monterey на Sonora, а также почищен диск
4+
5+
В связи с чем результаты значительно выросли,
6+
особеннно в области **GET** запросов, которые очень много работают с диском
7+
8+
Получается достаточное количества места на диске важный параметр
9+
10+
Либо стоит благословить Купертино
11+
12+
## Нагрузка
13+
### Характеристики
14+
Macbook Pro M1 16GB после перезапуска
15+
16+
17+
## Старый код
18+
До этого мы тестировали при 1 подключении и 1 потоке
19+
20+
Соответственно у нас было 2 ограничения:
21+
1. Мы могли упираться в производительность wrk2
22+
2. Наш код работал только в одном потоке, несмотря на количество селекторов, т.к. подключение 1
23+
24+
Поэтому перезапустим старый код и найдем новые rps
25+
### PUT
26+
27+
По [локам](old_base_lock.html) переодически можно заметить flush, который тормозит селекторы
28+
29+
Как мы видим [15000](old_base_wrk.txt) нагрузка настолько слабая,
30+
что нам не понадобились даже все селекторы (их только 4)
31+
[cpu](old_base_cpu.html)
32+
33+
Немного поискав
34+
* [30000](old_30000_wrk.txt)
35+
* [60000](old_60000_wrk.txt)
36+
* [52000](old_52000_wrk.txt)
37+
38+
остановился на [48000](old_stable_wrk.txt) RPS
39+
40+
[lock](old_stable_lock.html) из интересного можно заметить,
41+
что по окончании работы закрывается множество сессий
42+
43+
информация об этом пишется в лог и можно сделать выводы о том, что:
44+
1. не стоить злоупотреблять логами
45+
2. по этому столбику в целом можно смотреть о проблемности остальных локов
46+
*(чем он больше, тем менее значимы остальные локи)*
47+
48+
По [cpu](old_stable_cpu.html) видно, что большая часть ресурсов уходит на обработку подключений
49+
50+
5 min: [rps](old_stable_long_wrk.txt),
51+
[alloc](old_stable_long_alloc.html)
52+
[cpu](old_stable_long_cpu.html),
53+
[lock](old_stable_long_lock.html)
54+
55+
Как мы видим просадки теперь намного значительнее, т.к. flush блокирует все потоки
56+
57+
### GET
58+
59+
Немного поискав
60+
[60000](old_get_60000_wrk.txt)
61+
[80000](old_get_80000_wrk.txt)
62+
[85000](old_get_85000_wrk.txt)
63+
[90000](old_get_90000_wrk.txt)
64+
[100000](old_get_100000_wrk.txt)
65+
66+
Остановился на 80000 rps
67+
5 min:
68+
[alloc](old_get_stable_long_alloc.html)
69+
[cpu](old_get_stable_long_cpu.html)
70+
[lock](old_get_stable_long_lock.html)
71+
[rps](old_get_stable_long_wrk.txt)
72+
73+
Как мы видим из [lock](old_get_stable_long_lock.html) никаких локов на гет запросах нет, как и из кода
74+
75+
В целом ничего, кроме огромного роста производительности отметить нечего
76+
77+
И если в случае с **PUT** запросами он был всего в несколько раз,
78+
то здесь рост достаточно линеен, что может говорить о высоком параллелизме кода
79+
80+
## Новый код
81+
82+
### ArrayBlockingQueue
83+
84+
Производительность только упала
85+
86+
#### PUT
87+
88+
Как показали опыты: poolSize имеет значение.
89+
* 16:
90+
* * 43000: [alloc](new_put_a_16_43000_alloc.html),
91+
[cpu](new_put_a_16_43000_cpu.html),
92+
[lock](new_put_a_16_43000_lock.html),
93+
[rps](new_put_a_16_43000_wrk.txt)
94+
* * 48000: [alloc](new_put_a_16_48000_alloc.html),
95+
[cpu](new_put_a_16_48000_cpu.html),
96+
[lock](new_put_a_16_48000_lock.html),
97+
[rps](new_put_a_16_48000_wrk.txt)
98+
* * [50000](new_put_a_16_50000_wrk.txt)
99+
* 32
100+
* * [42000](new_put_a_32_42000_wrk.txt)
101+
* * 43000: [alloc](new_put_a_32_43000_alloc.html),
102+
[cpu](new_put_a_32_43000_cpu.html),
103+
[lock](new_put_a_32_43000_lock.html),
104+
[rps](new_put_a_32_43000_wrk.txt),
105+
* * [45000](new_put_a_32_45000_wrk.txt)
106+
* * [50000](new_put_a_32_50000_wrk.txt)
107+
108+
Чем больше потоков, тем сильнее они мешают друг-другу, что приводит к значительному снижению производительности
109+
110+
Так мы добрались до 8 максимальных (т.е. по числу ядер).
111+
* [alloc](new_put_a_2_8_48000_alloc.html)
112+
* [cpu](new_put_a_2_8_48000_cpu.html)
113+
* [lock](new_put_a_2_8_48000_lock.html)
114+
* [rps](new_put_a_2_8_48000_wrk.txt)
115+
116+
5 min: [alloc](new_put_a_2_8_stable_long_alloc.html),
117+
[cpu](new_put_a_2_8_stable_long_cpu.html),
118+
[lock](new_put_a_2_8_stable_long_lock.html),
119+
[rps](new_put_a_2_8_stable_long_wrk.txt)
120+
121+
Основные проблемы и заполнение очереди происходили при flush'ах таблицы, что вполне ожидаемо
122+
123+
#### GET
124+
125+
Здесь обратная ситуация, наши ответы достаточно долгие, а запросы наоборот быстрые, т.к. никаких данных считывать нам не нужно
126+
127+
И чем больше poolSize, тем больше допустимый RPS
128+
129+
### LinkedBlockingQueue
130+
131+
Несложно заметить, что у нас большие проблемы с локами. Связано это с тем, что в `ArrayBlockingQueue`
132+
одна блокировка на чтение и запись, поэтому окончательно разделить селекторы от воркеров не получилось
133+
134+
Воспользуемся `LinkedBlockingQueue`, у которой уже 2 разные блокировки на чтение и запись
135+
136+
#### PUT
137+
138+
Как мы видим, несмотря на то, что время самих блокировок для селекторов значительно уменьшилось
139+
140+
Что повысило скорость поступления новых задач (поэтому был повышел queueCapacity до 200, т.к. он набирался слишком быстро).
141+
142+
Однако, сама очередь достаточно медлена. Из-за чего общая производительность страдает.
143+
144+
* [40000](new_put_l_32_40000_wrk.txt)
145+
* 45000: [alloc](new_put_l_32_45000_alloc.html),
146+
[cpu](new_put_l_32_45000_cpu.html),
147+
[lock](new_put_l_32_45000_lock.html),
148+
[rps](new_put_l_32_45000_wrk.txt)
149+
* [48000](new_put_l_32_48000_wrk.txt)
150+
* [60000](new_put_l_32_60000_wrk.txt)
151+
152+
#### GET
153+
154+
На удивление, **GET'у** стало чуть лучше, но мне кажется, все в рамках погрешности
155+
156+
[rps](new_get_l_32_60000_wrk.txt),
157+
[alloc](new_get_l_32_60000_alloc.html),
158+
[cpu](new_get_l_32_60000_cpu.html),
159+
[lock](new_get_l_32_60000_lock.html)
160+
161+
### Давайте попробуем поделить
162+
163+
Поделим селекторы и воркеров на группы, чтобы уменьшить блокировку
164+
165+
Как мы видим, мы смогли замедлить downgrade касательно времени работы
166+
167+
Однако, как-то значительно улучшить производительность это нам не помогло
168+
169+
#### PUT
170+
171+
172+
* 40000:
173+
[alloc.html](1709758164_alloc.html)
174+
[cpu.html](1709758164_cpu.html)
175+
[lock.html](1709758164_lock.html)
176+
[wrk.txt](1709758164_wrk.txt)
177+
* 50000:
178+
[alloc](1709758118_alloc.html),
179+
[cpu](1709758118_cpu.html),
180+
[lock](1709758118_lock.html),
181+
[rps](1709758118_wrk.txt)
182+
183+
* 60000: [alloc](1709758089_alloc.html),
184+
[cpu](1709758089_cpu.html),
185+
[lock](1709758089_lock.html),
186+
[rps](1709758089_wrk.txt)
187+
188+
Локи в селекторах теперь незначительно, но тольку то ;)
189+
190+
## Вывод
191+
192+
Несмотря, на очевидность преимуществ, которые нам может подарить разделение селекторов
193+
194+
Оказывается, что на самом деле это довольно тонкая тема, в связи с многопоточностью и блокировками,
195+
которые нужно не забывать учитывать
196+
197+
К сожалению, не успел посмотреть `DiscardPolicy` с обрывом сокета для первой в очереди.
198+
Это вполне могло повлиять на среднее время ответа

src/main/java/ru/vk/itmo/test/kovalevigor/server/Responses.java

+4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ public Response toResponse() {
2121
return emptyResponse(responseCode);
2222
}
2323

24+
public String getResponseCode() {
25+
return responseCode;
26+
}
27+
2428
private static Response emptyResponse(String resultCode) {
2529
return new Response(resultCode, Response.EMPTY);
2630
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package ru.vk.itmo.test.kovalevigor.server;
2+
3+
import one.nio.http.HttpServer;
4+
import one.nio.http.HttpServerConfig;
5+
import one.nio.http.HttpSession;
6+
import one.nio.http.Request;
7+
import one.nio.server.SelectorThread;
8+
9+
import java.io.IOException;
10+
11+
public class ServerBasedOnStrategy extends HttpServer implements ServerFull {
12+
13+
private final ServerStrategy serverStrategy;
14+
15+
public ServerBasedOnStrategy(HttpServerConfig config, ServerStrategy serverStrategy) throws IOException {
16+
super(config);
17+
this.serverStrategy = serverStrategy;
18+
}
19+
20+
@Override
21+
public synchronized void start() {
22+
super.start();
23+
serverStrategy.start(this);
24+
}
25+
26+
@Override
27+
public void handleRequest(Request request, HttpSession session) throws IOException {
28+
serverStrategy.handleRequest(request, session);
29+
}
30+
31+
@Override
32+
public void handleDefault(Request request, HttpSession session) throws IOException {
33+
serverStrategy.handleDefault(request, session);
34+
}
35+
36+
@Override
37+
public void close() throws IOException {
38+
serverStrategy.close();
39+
}
40+
41+
@Override
42+
public SelectorThread[] getSelectors() {
43+
return selectors;
44+
}
45+
}

0 commit comments

Comments
 (0)