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

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) Выбираем самый свежий слейв. Промоутим его до мастера. Переключаем на него второй слейв.
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