Запузырил отчеты по домашкам

main
Andrey Ivanov 2021-02-17 13:05:39 +03:00 committed by ya@tiburon.su
parent f7cf301800
commit 847fb042a0
9 changed files with 320 additions and 28 deletions

View File

@ -0,0 +1,18 @@
## Домашние задания по курсу
### [01. Заготовка для социальной сети](test/dz001/README.md) (ЗАЧЕТ)
### [02. Производительность индексов](test/dz002/README.md) (ЗАЧЕТ)
-----
### [03. Полусинхронная репликация](test/dz003/README.md) (в процессе)
---
### [04. Лента новостей социальной сети](test/dz004/README.md) (не начата)
### [05. Репликация из MySQL в tarantool](test/dz005/README.md) (не начата)
### [06. Масштабируемая подсистема диалогов](test/dz006/README.md) (не начата)
### [07. Онлайн обновление ленты новостей](test/dz007/README.md) (не начата)
### [08. Разделение монолита на сервисы](test/dz008/README.md) (не начата)
### [09. Отказоустойчивость приложений](test/dz009/README.md) (не начата)
### [10. Сервис счетчиков](test/dz010/README.md) (не начата)
### [11. Внедрение docker и consul](test/dz011/README.md) (не начата)
### [12. Мониторинг](test/dz012/README.md) (не начата)
### [13. Проектная работа](test/dz013/README.md) (не начата)

0
cicd/init.sh Executable file → Normal file
View File

View File

@ -1,3 +1,4 @@
#[ЗАЧТЕНА](https://otus.ru/learning/61597/#/homework-chat/9332/)
# Заготовка для социальной сети # Заготовка для социальной сети
Цель: В результате выполнения ДЗ вы создадите базовый скелет социальной сети, который будет развиваться в дальнейших ДЗ. Цель: В результате выполнения ДЗ вы создадите базовый скелет социальной сети, который будет развиваться в дальнейших ДЗ.

32
test/dz002/README.md Normal file
View File

@ -0,0 +1,32 @@
#[ЗАЧТЕНА](https://otus.ru/learning/61597/#/homework-chat/9333/): [ОТЧЕТ](REPORT.md)
# Производительность индексов
Цель: В результате выполнения ДЗ вы создадите набор тестовых данных для проведения нагрузочного тестирования, подберете наиболее подходящие индексы и проведете тесты производительности.
### В данном задании тренируются навыки:
- генерация тестовых данных;
- работа с индексами;
- нагрузочное тестирование;
### План выполнения:
1) Сгенерировать любым способ 1,000,000 анкет. Имена и Фамилии должны быть реальными (чтобы учитывать селективность индекса)
2) Реализовать функционал поиска анкет по префиксу имени и фамилии (одновременно) в вашей социальной сети (запрос в форме firstName LIKE ? and secondName LIKE ?). Сортировать вывод по id анкеты. Использовать InnoDB движок.
3) С помощью wrk провести нагрузочные тесты по этой странице. Поиграть с количеством одновременных запросов. 1/10/100/1000.
4) Построить графики и сохранить их в отчет
5) Сделать подходящий индекс.
6) Повторить пункт 3 и 4.
7) В качестве результата предоставить отчет в котором должны быть:
- графики latency до индекса;
- графики throughput до индекса;
- графики latency после индекса;
- графики throughput после индекса;
- запрос добавления индекса;
- explain запросов после индекса;
- объяснение почему индекс именно такой;
ДЗ принимается в виде отчета по выполненной работе.
Критерии оценки: Оценка происходит по принципу зачет/незачет.
###Требования:
Правильно выбраны индексы.
Нагрузочное тестирование проведено и результаты адекватны.
Рекомендуем сдать до: 01.02.2021

42
test/dz002/REPORT.md Normal file
View File

@ -0,0 +1,42 @@
### 1. Графики Latency и Kb/s от кол-ва одновременных запросов, до и после установки индексов.
![mountains](img/diagramms.jpg "Диаграммы нагрузки")
### 2. В случае использования индекса indNameSurname:
- #### Запрос на добавление индексов:
```
ALTER TABLE `users` ADD INDEX `indNameSurname` (`Name`, `Surname`);
```
- #### Explain запроса:
```
EXPLAIN SELECT
users.id as id,
users.name as name,
users.surname as surname,
users.birthdate as birthdate,
users.gender as gender,
users.city as city
FROM
users
WHERE users.Name LIKE "ан%" AND users.Surname LIKE "ан%"
ORDER BY id
```
### 3. В случае использования индекса indSurnameName:
- #### Запрос на добавление индексов:
```
ALTER TABLE `users` ADD INDEX `indSurnameName` (`Surname`, `Name`);
```
- #### Explain запроса:
```
EXPLAIN SELECT
users.id as id,
users.name as name,
users.surname as surname,
users.birthdate as birthdate,
users.gender as gender,
users.city as city
FROM
users
WHERE users.Name LIKE "ан%" AND users.Surname LIKE "ан%"
ORDER BY id
```
#### 4. РезюмеЖ
Для конечной оптимизации используется составной индекс `('Surname', 'Name')` потому, что в запросе используется объединение AND условий LIKE ?%. Mysql в этом случае ищет по составному индексу и объединяет строки без сортировки. Именно поэтому, приходится принудительно сортировать результаты. Порядок полей выбран с точки зрения селективности. В реальной обстановке поле «Фамилия» все же более селективно чем «Имя». Плюс к этому, мы видим в EXPLAIN запроса, что в случае использования индекса `('Surname', 'Name')` mysql применяет Multi-Range Read оптимизацию, позволяющую линеаризовать процедуру чтения с диска. Возможно за этот счет значительно повысилась скорость передачи данных? по сравнению с индексом `('Name', 'Surname')`.

View File

@ -1,3 +1,4 @@
#[в процессе](https://otus.ru/learning/61597/#/homework-chat/9334/): [ОТЧЕТ](REPORT.md)
#Полусинхронная репликация #Полусинхронная репликация
В результате выполнения ДЗ вы настроите полусинхронную репликацию, протестируете ее влияние на производительность системы и убедитесь, что теперь вы не теряете транзакции в случае аварии. В результате выполнения ДЗ вы настроите полусинхронную репликацию, протестируете ее влияние на производительность системы и убедитесь, что теперь вы не теряете транзакции в случае аварии.
@ -23,7 +24,7 @@
12) Выбираем самый свежий слейв. Промоутим его до мастера. Переключаем на него второй слейв. 12) Выбираем самый свежий слейв. Промоутим его до мастера. Переключаем на него второй слейв.
13) Проверяем, есть ли потери транзакций. 13) Проверяем, есть ли потери транзакций.
Результатом сдачи ДЗ будет в виде исходного кода на github и отчета в текстовом виде, где вы отразите как вы выполняли каждый из пунктов. Результатом сдачи ДЗ будет в виде исходного кода на github и [отчета в текстовом виде](REPORT.md), где вы отразите как вы выполняли каждый из пунктов.
Критерии оценки: Оценка происходит по принципу зачет/незачет. Критерии оценки: Оценка происходит по принципу зачет/незачет.
### Требования: ### Требования:

225
test/dz003/REPORT.md Normal file
View File

@ -0,0 +1,225 @@
### 1. Настраиваем асинхронную репликацию.
Я решил сделать сразу три хоста - один мастер и два слейва, чтобы к этому не возвращаться в 5-м пункте.
- #### [my.cnf мастера](../../cicd/mysql/mysql_master.conf):
```
[mysqld]
skip-host-cache
skip-name-resolve
server-id = 1
log_bin = /var/log/mysql/mysql-bin.log
binlog_do_db = app
```
- #### [my.cnf первого слэйва](../../cicd/mysql/mysql_slave1.conf):
```
[mysqld]
skip-host-cache
skip-name-resolve
server-id = 2
log_bin = /var/log/mysql/mysql-bin.log
relay-log = /var/log/mysql/mysql-relay-bin.log
binlog_do_db = app
```
- #### [my.cnf первого слэйва](../../cicd/mysql/mysql_slave2.conf):
```
[mysqld]
skip-host-cache
skip-name-resolve
server-id = 3
log_bin = /var/log/mysql/mysql-bin.log
relay-log = /var/log/mysql/mysql-relay-bin.log
binlog_do_db = app
```
- #### [Инициализация кластера](../../cicd/init.sh):
- на мастере создаем базу, пользователя для работы приложения и пользователя для репликации:
```
CREATE DATABASE IF NOT EXISTS app CHARACTER SET utf8 COLLATE utf8_general_ci;
GRANT ALL ON app.* TO "app"@"%" IDENTIFIED BY "app";
GRANT REPLICATION SLAVE ON *.* TO "mydb_slave_user"@"%" IDENTIFIED BY "mydb_slave_pwd";
FLUSH PRIVILEGES;
```
- на обоих слэйвах создаем базу и пользователя для работы приложения:
```
CREATE DATABASE IF NOT EXISTS app CHARACTER SET utf8 COLLATE utf8_general_ci;
GRANT ALL ON app.* TO "app"@"%" IDENTIFIED BY "app"; FLUSH PRIVILEGES;
```
- определяем текущий IP адрес мастера:
```
docker inspect --format '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' "mysql_master"
```
- определяем текущий лог файл мастера и позицию в нем:
```
mysql -u root -e "SHOW MASTER STATUS"' | grep mysq | awk '{print $1}'
mysql -u root -e "SHOW MASTER STATUS"' | grep mysq | awk '{print $2}'
```
- на обоих слейвах назначаем мастера и запускаем репликацию:
```
CHANGE MASTER TO MASTER_HOST={IP_мастера},MASTER_USER='mydb_slave_user',MASTER_PASSWORD='mydb_slave_pwd',MASTER_LOG_FILE={текущий_лог},MASTER_LOG_POS={текущая_позиция};
START SLAVE;
```
### 2. Выбираем 2 любых запроса на чтения (в идеале самых частых и тяжелых по логике работы сайта) и переносим их на чтение со слейва.
Я решил поэкспериментировать с теми же поисковыми запросами, над которыми мы экспериментировали в [ДЗ002](../dz002/REPORT.md). Тем более, что все инструменты для этого уже есть в наличии (wrk).
- #### Добавил в [структуру конфига](../../internal/models/config.go) адреса мастера и двух слейвов:
```
type DSN struct {
Master string
Slave1 string
Slave2 string
Port string
User string
Pass string
Base string
}
```
- #### В [хэндлере страницы app:port/search](../../internal/handlers/handlers.go) создал селектор, который направляет запросы чтения на первый слейв, если он присутствует в конфигурации:
```
db := app.DBMaster
if app.Config.DSN.Slave1!="" {
db = app.DBSlave1
}
```
### 3. Делаем нагрузочный тест по странице, которую перевели на слейв до и после репликации. Замеряем нагрузку мастера (CPU, la, disc usage, memory usage).
- #### Разворачиваем prom&grafana в docker настраиваем dashboard grafana на docker контейнеры
```
sudo make prom-up
```
- #### Запускаем приложение с подключением только к мастеру и с помощью wrk и [lua скрипта](scripts/post.lua) нагружаем страницу app:port/search:
```
sudo make app-up
sudo docker run --rm -v /root/scripts:/scripts williamyeh/wrk -t1 -c10 -d5m --timeout 30s http://localhost:8080/search -s /scripts/post.lua -- debug true
```
- #### Идем в [графану](http://localhost:3001/) и наблюдаем нагрузку на мастер.
- #### Ждем пока wrk отработает:
```
Running 5m test @ http://192.168.1.66:8080/search
1 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 5.83s 1.74s 13.29s 77.58%
Req/Sec 3.57 4.74 30.00 82.50%
511 requests in 5.00m, 18.69MB read
Requests/sec: 1.70
Transfer/sec: 63.79KB
```
- #### Подключаем первый слэйв в приложении, добавлением в docker-compose.yml переменной окружения:
```
APP_DSN_SLAVE1: mysql_slave1
```
- #### Перезапускаем контейнер с приложением (в моем случае, перезапускаются и базу, но для данного эксперимента это не принципиально) и нагружаем ту же страницу тем же запросом, с помощью wrk:
```
sudo make app-reload
sudo docker run --rm -v /root/scripts:/scripts williamyeh/wrk -t1 -c10 -d5m --timeout 30s http://localhost:8080/search -s /scripts/post.lua -- debug true
```
- #### Идем в [графану](http://localhost:3001/) и наблюдаем нагрузку на слэйв.
- #### Ждем пока wrk отработает:
```
Running 5m test @ http://192.168.1.66:8080/search
1 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 32.12ms 31.59ms 561.62ms 90.65%
Req/Sec 373.34 147.37 610.00 68.45%
110834 requests in 5.00m, 433.90MB read
Non-2xx or 3xx responses: 110834
Requests/sec: 369.39
Transfer/sec: 1.45MB
```
- #### Получаем график нагрузки:
![График нагрузки на контейнерах приложения](img/dz003_part1.jpg "График нагрузки на контейнерах приложения")
### 4. ОПЦИОНАЛЬНО: в качестве конфига, который хранит IP реплики сделать массив для легкого добавления реплики. Это не самый правильный способ балансирования нагрузки. Поэтому опционально.
Не очень понял, что именно нужно сделать. Если речь о конфиге приложения, я пока сделал отдельные переменные для каждого сервера БД. Если потребуется, заменю срезом. Пока пусть останется так.
### 5. Настроить 2 слейва и 1 мастер.
Пропускаю этот пункт, т.к. все уже было сделано в п.1
### 6. Включить row-based репликацию.
- #### Добавляем в my.cnf мастера строки:
```
binlog_format=ROW
binlog-checksum=crc32
```
- #### Добавляем в my.cnf обоих слейвов строки:
```
binlog_format=ROW
binlog-checksum=crc32
```
- #### Запускаем кластер и приложение:
```
sudo make app-up
```
### 7. Включить GTID.
- #### Добавляем в my.cnf мастера строки:
```
gtid-mode=on
enforce-gtid-consistency=true
```
- #### Добавляем в my.cnf обоих слейвов строки:
```
gtid-mode=on
enforce-gtid-consistency=true
```
- #### Запускаем кластер и приложение:
```
sudo make app-up
```
### 8. Настроить полусинхронную репликацию.
- #### Включаем динамическую загрузку модулей и полусинхронную репликацию с таймаутом 1с в my.cnf на мастере:
```
have_dynamic_loading=YES
rpl_semi_sync_master_enabled=1
rpl_semi_sync_master_timeout=1000
```
- #### Включаем динамическую загрузку модулей и полусинхронную репликацию в my.cnf на обоих слейвах:
```
have_dynamic_loading=YES
rpl_semi_sync_master_enabled=1
```
- #### Устанавливаем semisync плагин на мастере:
```
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
```
- #### Устанавливаем semisync плагин на обоих слейвах:
```
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
```
- #### Проверяем на всех хостах, установлен ли плагин:
```
SELECT PLUGIN_NAME, PLUGIN_STATUS FROM INFORMATION_SCHEMA.PLUGINS WHERE PLUGIN_NAME LIKE '%semi%';
```
- #### Запускаем кластер и приложение:
```
sudo make app-up
```
### 9. Создать нагрузку на запись в любую тестовую таблицу. На стороне, которой нагружаем считать, сколько строк мы успешно записали.
### 10. С помощью kill -9 убиваем мастер MySQL.
### 11. Заканчиваем нагрузку на запись.
### 12. Выбираем самый свежий слейв. Промоутим его до мастера. Переключаем на него второй слейв.
### 13. Проверяем, есть ли потери транзакций.
Встроен запуск prometeus, grafana и т.д.
Графана доступна на http://localhost:3001/
$ sudo docker run --rm -v /root/scripts:/scripts williamyeh/wrk -t1 -c10 -d5m --timeout 30s http://192.168.1.66:8080/search -s /scripts/post.lua -- debug true
Running 5m test @ http://192.168.1.66:8080/search
1 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 5.83s 1.74s 13.29s 77.58%
Req/Sec 3.57 4.74 30.00 82.50%
511 requests in 5.00m, 18.69MB read
Requests/sec: 1.70
Transfer/sec: 63.79KB
$ sudo make app-reload
...
...
...
$ sudo docker run --rm -v /root/scripts:/scripts williamyeh/wrk -t1 -c10 -d5m --timeout 30s http://192.168.1.66:8080/search -s /scripts/post.lua -- debug true
Running 5m test @ http://192.168.1.66:8080/search
1 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 32.12ms 31.59ms 561.62ms 90.65%
Req/Sec 373.34 147.37 610.00 68.45%
110834 requests in 5.00m, 433.90MB read
Non-2xx or 3xx responses: 110834
Requests/sec: 369.39
Transfer/sec: 1.45MB

View File

@ -1,27 +0,0 @@
Встроен запуск prometeus, grafana и т.д.
Графана доступна на http://localhost:3001/
$ sudo docker run --rm -v /root/scripts:/scripts williamyeh/wrk -t1 -c10 -d5m --timeout 30s http://192.168.1.66:8080/search -s /scripts/post.lua -- debug true
Running 5m test @ http://192.168.1.66:8080/search
1 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 5.83s 1.74s 13.29s 77.58%
Req/Sec 3.57 4.74 30.00 82.50%
511 requests in 5.00m, 18.69MB read
Requests/sec: 1.70
Transfer/sec: 63.79KB
$ sudo make app-reload
...
...
...
$ sudo docker run --rm -v /root/scripts:/scripts williamyeh/wrk -t1 -c10 -d5m --timeout 30s http://192.168.1.66:8080/search -s /scripts/post.lua -- debug true
Running 5m test @ http://192.168.1.66:8080/search
1 threads and 10 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 32.12ms 31.59ms 561.62ms 90.65%
Req/Sec 373.34 147.37 610.00 68.45%
110834 requests in 5.00m, 433.90MB read
Non-2xx or 3xx responses: 110834
Requests/sec: 369.39
Transfer/sec: 1.45MB