Skip to content

Commit 5b4a0d6

Browse files
Игорь Ковалев HW2 (#50)
* add dao * fix dependencies * simple server * create all routes * fix cringe * tests * update dao to last version :) * add scripts * partly stage1 * vivods * мега вывод * code climate * new ideas * hw2 * fix codeclimate * code refactor * gg wp * refactor reports * hw2 --------- Co-authored-by: Alexey Shik <58121508+AlexeyShik@users.noreply.github.com>
1 parent 4d38ada commit 5b4a0d6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+873
-87
lines changed

src/main/java/ru/vk/itmo/test/kovalevigor/config/DaoServerConfig.java

+4
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,8 @@
99
public class DaoServerConfig extends HttpServerConfig {
1010
public Path basePath;
1111
public long flushThresholdBytes;
12+
public int corePoolSize = 2;
13+
public int maximumPoolSize = 20;
14+
public long keepAliveTime = 100;
15+
public int queueCapacity = 1000;
1216
}
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)
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
#!/bin/bash
22
NAME=$(date +"%s")
33
JFR="../../info-$NAME.jfr"
4-
(wrk2 -c 1 -t 1 -L -d $1 -R $2 -s "../lua/$3.lua" http://localhost:8080 > "../../html/${NAME}_wrk.txt") &
5-
./ap/bin/asprof -e cpu,alloc -d $1 -f $JFR MainServer
4+
PREFIX="../../html/stage2"
5+
(wrk2 -c 128 -t 8 -L -d $1 -R $2 -s "../lua/$3.lua" http://localhost:8080 > "${PREFIX}/${NAME}_wrk.txt") &
6+
./ap/bin/asprof -t -e cpu,alloc,lock -d $1 -f $JFR MainServer
67

78
wait
8-
java -cp ./ap/lib/converter.jar jfr2flame $JFR > "../../html/${NAME}_cpu.html"
9-
java -cp ./ap/lib/converter.jar jfr2flame --alloc $JFR > "../../html/${NAME}_alloc.html"
9+
java -cp ./ap/lib/converter.jar jfr2flame --threads $JFR > "${PREFIX}/${NAME}_cpu.html"
10+
java -cp ./ap/lib/converter.jar jfr2flame --threads --alloc $JFR > "${PREFIX}/${NAME}_alloc.html"
11+
java -cp ./ap/lib/converter.jar jfr2flame --threads --lock $JFR > "${PREFIX}/${NAME}_lock.html"
1012
rm $JFR

src/main/java/ru/vk/itmo/test/kovalevigor/reports/stage1.md

+27-27
Original file line numberDiff line numberDiff line change
@@ -37,28 +37,28 @@ Macbook Pro M1 16GB после перезапуска
3737
#### PUT-запросы
3838
Изначально мы прощупываем точку разладки для **PUT** запросов
3939

40-
[1](html/put_lower_wrk.txt),
41-
[2](html/put_upper_wrk.txt),
42-
[3](html/put_middle_1.txt),
43-
[4](html/put_middle_2.txt),
44-
[5](html/put_middle_3.txt),
45-
[6](html/put_middle_4.txt)
40+
[1](html/stage1/put_lower_wrk.txt),
41+
[2](html/stage1/put_upper_wrk.txt),
42+
[3](html/stage1/put_middle_1.txt),
43+
[4](html/stage1/put_middle_2.txt),
44+
[5](html/stage1/put_middle_3.txt),
45+
[6](html/stage1/put_middle_4.txt)
4646

4747
Можно обратить внимание, что flamegraph'ы при этом не сильно отличаются
4848

49-
[1](html/put_lower_cpu.html),
50-
[2](html/put_upper_cpu.html)
49+
[1](html/stage1/put_lower_cpu.html),
50+
[2](html/stage1/put_upper_cpu.html)
5151

5252
Видимо, это просто может сказать нам о некоем пределе нашей производительности
5353

5454
В итоге остановился на 13000 RPS, т.к. там есть более ощутимый скачок, чем на 11500
5555

56-
[300 секунд по 13000 RPS на пустую базу](html/put_request_wrk.txt)
56+
[300 секунд по 13000 RPS на пустую базу](html/stage1/put_request_wrk.txt)
5757

58-
Если посмотреть на [аллокации](html/put_request_alloc.html),
58+
Если посмотреть на [аллокации](html/stage1/put_request_alloc.html),
5959
то наше DAO почти ничего не аллоцирует, все уходит на сервер
6060

61-
На [cpu](html/put_request_cpu.html), т.к. мы вынесли flush в отдельный поток (самая левая гора),
61+
На [cpu](html/stage1/put_request_cpu.html), т.к. мы вынесли flush в отдельный поток (самая левая гора),
6262
то он незаметно, что он как либо блокирует, сохранение наших записей.
6363

6464
Однако, можно заметить, что 30% от времени отправки ответа занимает помещенеие entity в мапу
@@ -75,29 +75,29 @@ Macbook Pro M1 16GB после перезапуска
7575

7676
*Как можно заметить после первой же нагрузки, что происходит огромная просадка на существенной части запросов*
7777

78-
*[wrk](html/get_many_misses_wrk.txt)*
78+
*[wrk](html/stage1/get_many_misses_wrk.txt)*
7979

8080
*И это оказывается фейком, потому что одновременно с запросами работал optimizer*
8181

8282
Из-за того, что **PUT** запросы создают записи в слишком большом диапазоне у нас много 400.
8383
Однако, давайте и тут найдем точку разладки
8484

85-
[7000rps](html/get_7000_wrk.txt),
86-
[8000rps](html/get_8000_wrk.txt),
87-
[9000rps](html/get_9000_wrk.txt)
88-
[10000rps](html/get_10000_wrk.txt)
85+
[7000rps](html/stage1/get_7000_wrk.txt),
86+
[8000rps](html/stage1/get_8000_wrk.txt),
87+
[9000rps](html/stage1/get_9000_wrk.txt)
88+
[10000rps](html/stage1/get_10000_wrk.txt)
8989

9090
Возьмем 8000, т.к. на мой взгляд наиболее оптимальное падение производительности
9191

92-
[300 секунд по 8000 RPS](html/get_misses_request_wrk.txt)
92+
[300 секунд по 8000 RPS](html/stage1/get_misses_request_wrk.txt)
9393

94-
Как мы видим из [cpu](html/get_misses_request_cpu.html) огромное количество времени уходит на бинарный поиск
94+
Как мы видим из [cpu](html/stage1/get_misses_request_cpu.html) огромное количество времени уходит на бинарный поиск
9595

9696
*Вероятнее всего, это связано с запросами к несуществующим ключам,
9797
т.к. для для проверки нам будет необходимо обойти все таблицы
9898
*(20 по 45MB)**
9999

100-
Также можно заметить,что теперь у нас присутсвует огромное количество [аллокаций](html/get_misses_request_alloc.html)
100+
Также можно заметить,что теперь у нас присутсвует огромное количество [аллокаций](html/stage1/get_misses_request_alloc.html)
101101
для бинарного поиска
102102

103103
Также из интересного можно заметить, что столбик с созданием итератора занимает `3%`,
@@ -108,16 +108,16 @@ Macbook Pro M1 16GB после перезапуска
108108

109109
Так 400 будет намного-намного меньше)
110110

111-
[10000_wrk](html/get_n_10000_wrk.txt),
112-
[11000_wrk](html/get_n_11000_wrk.txt),
113-
[13000_wrk](html/get_n_13000_wrk.txt),
114-
[15000_wrk](html/get_n_15000_wrk.txt)
111+
[10000_wrk](html/stage1/get_n_10000_wrk.txt),
112+
[11000_wrk](html/stage1/get_n_11000_wrk.txt),
113+
[13000_wrk](html/stage1/get_n_13000_wrk.txt),
114+
[15000_wrk](html/stage1/get_n_15000_wrk.txt)
115115

116116
Как мы видим, примерно 25% - это промахи. Возьмем 10000 RPS
117117

118-
[300 секунд по 10000 RPS](html/get_n_request_wrk.txt)
118+
[300 секунд по 10000 RPS](html/stage1/get_n_request_wrk.txt)
119119

120-
[cpu](html/get_n_request_cpu.html)
120+
[cpu](html/stage1/get_n_request_cpu.html)
121121
Как мы видим время поиска на диске сократилось в процентном соотношении, т.е.
122122
мы стали чаще попадать в память.
123123

@@ -127,7 +127,7 @@ Macbook Pro M1 16GB после перезапуска
127127

128128
Однако, проблема с поиском никуда не делась. Что впринципе видно из графиков
129129

130-
[Аллокации](html/get_n_request_alloc.html) также демонстрируют нам, что искать мы стали существенно меньше,
130+
[Аллокации](html/stage1/get_n_request_alloc.html) также демонстрируют нам, что искать мы стали существенно меньше,
131131
т.к. теперь столбик `nio` хотя бы различим
132132
#### Other
133133

@@ -196,6 +196,6 @@ B+-tree - круто, блюм-фитр - респект
196196

197197
Хотя при этом время ответа значительно увеличилось. Возможно, комп уже загадился, либо я что-то не понял
198198

199-
PUT: [wrk](html/put_without_gen_wrk.txt), [alloc](html/put_without_gen_alloc.html), [cpu](html/put_without_gen_cpu.html)
199+
PUT: [wrk](html/stage1/put_without_gen_wrk.txt), [alloc](html/stage1/put_without_gen_alloc.html), [cpu](html/stage1/put_without_gen_cpu.html)
200200
GET: [wrk](html/Fget_without_gen_wrk.txt), [alloc](html%2Fget_without_gen_alloc.html), [cpu](html%2Fget_without_gen_cpu.html)
201201

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+
Это вполне могло повлиять на среднее время ответа

0 commit comments

Comments
 (0)