|
| 1 | +# Интро |
| 2 | + |
| 3 | +## Что за проект |
| 4 | + |
| 5 | +Команда `Unity` в `Rambler&Co`. |
| 6 | + |
| 7 | +Мы занимаемся разработкой продуктов, обеспечивающих работу редакций интернет-изданий - таких как [ferra.ru](https://www.ferra.ru/), [secretmag.ru](https://secretmag.ru/) и др. |
| 8 | + |
| 9 | +Сайты разрабатываются отдельно группой фронтенда. На бэкенде есть набор приложений и сервисов, ключевые это: |
| 10 | + |
| 11 | +### krang |
| 12 | + |
| 13 | +`CMS` на `postgres`, админка в которой работают редакции (фронт разрабатывается отдельной командой). |
| 14 | + |
| 15 | +### bebop |
| 16 | + |
| 17 | +Апишка на `mongoDB`, отдающая данные сайтам. |
| 18 | + |
| 19 | +## Как долго уже разрабатывается |
| 20 | + |
| 21 | +Более 5 лет. |
| 22 | + |
| 23 | +## Как дела с перформансом |
| 24 | + |
| 25 | +### krang |
| 26 | + |
| 27 | +Некоторые операции, такие как создание топика и др., могут занимать существенное время. |
| 28 | + |
| 29 | +В рамках ДЗ мы попытаемся сконцентрировться на этом приложении. |
| 30 | + |
| 31 | +### bebop |
| 32 | + |
| 33 | +Думаю, часть апи практически никогда не играет роль боттлнека по времени. Как обсуждалось на лекциях, сайты СМИ как правило тяжеловесны, и на их фоне выдача подготовленных данных из `mongoDB` не будет играть существенной роли. |
| 34 | + |
| 35 | +## Есть ли мониторинг |
| 36 | + |
| 37 | +- `New Relic` (подключен `krang`, `bebop` - планируется); |
| 38 | +- `Kibana` с дашбордами; |
| 39 | +- что-то еще, чего пока не видел. |
| 40 | + |
| 41 | +## Можете ли вы навскидку предположить где в проекте есть что оптимизировать |
| 42 | + |
| 43 | +Когда получил доступ в `NewRelic` обратил внимание на распухающее время `Redis zscan`, за последнее 3 месяца - это абсолютный лидер среди тяжеловесных операций. Задача в работе. |
| 44 | + |
| 45 | +## Какова ваша роль в проекте, как давно работаете, чем занимаетесь |
| 46 | + |
| 47 | +Инженер-разработчик `Ruby` группы бэкенд, в компании 1.5 года. Занимаюсь разработкой приложений/сервисов на `Ruby`, вкл. написание тестов, исправление багов и пр. |
| 48 | + |
| 49 | +# Оптимизация Redis zscan |
| 50 | + |
| 51 | +В последнее время стали наблюдаться проблемы с `redis` и `sidekiq`, возросло кол-во занятых воркеров / ноду. |
| 52 | + |
| 53 | +Анализ начался с отчетов `New relic`. |
| 54 | + |
| 55 | +Если рассматривать операции по бд, то `redis zscan` в абсолютных лидерах: |
| 56 | + |
| 57 | +<img src="/screenshots/top_20_db_operations_before.png" width="200" /> |
| 58 | + |
| 59 | +Абсолютно большая часть нагрузки приходится на джобу `Sidekiq/Social::CountUpdaterJob`: |
| 60 | + |
| 61 | +<img src="/screenshots/redis_zscan_time_consumption_by_caller.png" width="200" /> |
| 62 | + |
| 63 | +Время ответа `redis zscan` в рамках `CountUpdaterJob` за последние 3 месяца увеличилось примерно в 2 раза (1160ms → 2050ms): |
| 64 | + |
| 65 | +<img src="/screenshots/job_breakdown.png" width="200" /> |
| 66 | + |
| 67 | +Задача данной джобы заключается в сборе данных о репостах из социальных сетей (в нашем случае `vk` и до недавнего времени - `facebook`). |
| 68 | + |
| 69 | +Наличие `redis zscan` в джобе обусловлено тем, что при постановке джобы мы ищем дубликаты по объектам - с целью минимизации общего кол-ва запросов: требование связано с действующим на текущий момент ограничением `не более 1 запроса в 20 секунд`. |
| 70 | + |
| 71 | +В связи с подключением новых проектов, база за последние 3 месяца выросла - пропорциональным образом (`O(N)`) возросло и время ответа `redis zscan`. |
| 72 | + |
| 73 | +Главной целью стал поиск путей отказа от проверки дублирования и как следствие - использования `redis zscan`. |
| 74 | + |
| 75 | +Первая мысль была в том, чтобы найти ручку `vk`, которая собирает данные по многим топикам сразу, пакетно: возможно, с момента нашего последнего обновления такая возможность появилась, но такая ручка не нашлась. |
| 76 | + |
| 77 | +Потом обратил внимание на то, что требование в установленном на нашей стороне ограничении было актуально для `facebook`, по которому мы в настоящий момент статистику не собираем. Вариант, который я предложил, заключается в отключении `mutex` и исключении проверок на дубликаты - выполнять запросы без ограничений (т.к. со стороны апи `vk` его и нет) - таким образом, мы увеличим кол-во запросов, но это позволит нам решить найденную проблему с `redis zscan`. |
| 78 | + |
| 79 | +До тех пор мы тестируем решение, которое связано с уменьшением таймаута `mutex`. То есть нечто среднее между полным отключением проверки и текущим вариантом. |
| 80 | + |
| 81 | +# Результаты |
| 82 | + |
| 83 | +Уже сейчас мы вернулись к показателям 3-месячной давности, и в джобе: |
| 84 | + |
| 85 | +<img src="/screenshots/job_after.png" width="200" /> |
| 86 | + |
| 87 | +И по `redis zscan` в целом: |
| 88 | + |
| 89 | +<img src="/screenshots/redis_zscan_after_2.png" width="200" /> |
| 90 | + |
| 91 | +Это сказалось на времени обработки и других важных операциях в системе - например, `topics#create`: |
| 92 | + |
| 93 | +<img src="/screenshots/topics_create.png" width="200" /> |
| 94 | + |
| 95 | +Что важно, нагрузка на `redis` в целом также существенно спала: |
| 96 | + |
| 97 | +<img src="/screenshots/redis.png" width="200" /> |
| 98 | + |
| 99 | +Мы планируем еще понаблюдать за ситуацией, и после финализации решения установим защитный алерт для защиты метрики. |
| 100 | + |
| 101 | +# Профит |
| 102 | + |
| 103 | +Ориентировочный срок окупаемости - 3 месяца. |
| 104 | + |
| 105 | +```ruby |
| 106 | +# стоимость разработчика |
| 107 | +dev_cost_rub_month = 4_000 * 100 |
| 108 | +=> 400000 # (руб/месяц) |
| 109 | +dev_cost_rub_day = dev_cost_rub_month / 20 |
| 110 | +=> 20000 # (руб/день) |
| 111 | + |
| 112 | +# стоимоть требуемого увеличения мощностей (руб) |
| 113 | +# NOTE. сейчас redis работает на двух инстансах, |
| 114 | +# таким образом, для увеличения мощностей пропорционально возросшей нагрузки, |
| 115 | +# нам нужно 2 дополнительных сервера |
| 116 | +server_cost_rub_month = 3_000 |
| 117 | +=> 3000 |
| 118 | +redis_cost_rub_month = server_cost_rub_month * 2 |
| 119 | +=> 6000 |
| 120 | + |
| 121 | +# стоимость оптимизации (руб) |
| 122 | +task_cost_rub = dev_cost_rub_day * 1 |
| 123 | +=> 20000 |
| 124 | + |
| 125 | +# срок окупаемости (месяц) |
| 126 | +time_to_profit_month = task_cost_rub / redis_cost_rub_month |
| 127 | +=> 3 |
| 128 | +``` |
| 129 | + |
| 130 | +Без учета того, что: |
| 131 | +- общая нагрузка на `redis`, по сравнению с показателями 3-месячной давности, спала примерно в 2.5 раза; |
| 132 | +- ввод дополнительного сервера не защитил бы нас от возможного возвращения проблемы в будущем; |
| 133 | +- не только `CountUpdaterJob`, но и другие операции, использующие `redis`, стали выполняться быстрее. |
0 commit comments