Date post: | 07-Jan-2017 |
Category: |
Software |
Upload: | mailru-group |
View: | 7,215 times |
Download: | 1 times |
Особенности работы backend для мобильных приложений или Python Django UWSGI в продакшен
Дмитрий Швеенков, руководитель команды разработки
Мобильные приложения
Новости Гороскопы
3
О чем доклад
- Особенности разработки backend для мобильных приложений
- Измерение времени ответа backend
- Особенности работы стека python – django – uwsgi – nginx
- Оптимизация производительности
- Инструменты и подходы, которые мы используем
4
Задачи backend
- Агрегация информации о новостных ресурсах
- Хранение медиа контента
- Кэширование данных
- JSON API
- Работа с изображениями (crop, resize)
5
Особенности разработки API
- Разнообразие устройств и ОС:
- Планшеты
- Смартфоны
- iOS
- Android
- Windows phone
- и т.п.
- Редизайн мобильных приложений
- Версионирование API
- Медленное обновление версий приложений
- Большая пиковая нагрузка
6
Время запуска приложения
Время запуска влияет на ретеншен - http://bit.ly/2cDc60a
7
Допустимое время ответа backend
Каким должен быть response_time?
- 1 секунда, это быстро?
- 5 секунд?
- 200 миллисекунд, норма
8
Как измерить время работы backend?
- Измерения на backend - timeit $ python -m timeit '"-".join(str(n) for n in range(100))'
- Измерения на клиенте - wrk, ab, siege
- Nginx access logs log_format main '$remote_addr - [$time_local] "$request" ' '$status $bytes_sent $request_length '
'$request_time $upstream_response_time'
9
Графики rps и upstream_time
10
upstream_response_time хороший показатель?
Среднее для upstream_response_time(20 + 10 + 20 + 10 + 10 + 20 + 500 + 500 + 500 + 400) / 10 = 199мс
Персентили http://bit.ly/2d4z5zi $ fgrep "13/Sep/2016:10:" access.log | awk '{print $NF}' | sort -n | python percentile_stdin.py
11
Сбор метрик в продакшен
- Statsd+Graphite+Grafanahttps://github.com/bitly/statsdaemonhttp://graphiteapp.org/ http://grafana.org/
- Отправка из uwsgi --carbon 127.0.0.1:2003
- Diamond для cpu, la, network и iostathttps://github.com/python-diamond/Diamond
- Хранение истории
- Группировка по платформам ios/android
- Автоматизация сравнения графиковhttp://bit.ly/2d8fcHl
12
- Рост кол-ва пользователей приводит к росту qps к backend
- Рост qps потребляет ресурсы сервера
- Для обработки запросов требуются uwsgi-workers
Как выбрать оптимальное количество workers? http://bit.ly/2cDjGpA
cpu cores x 2
Рост нагрузки, стек python – django – uwsgi – nginx
13
Как uWSGI обрабатывает входящие запросы?
Рост нагрузки
bindlisten fork
while true:
accept
uWSGI master uWSGI worker
14
Рост нагрузки
- uwsgi options --thunder-lock - http://bit.ly/2ckdRPe
- David Cramer, discus.com - http://bit.ly/2cxckEX
15
Рост нагрузки
Параметры nginx http://bit.ly/2cfxEkh:
- uwsgi_buffers
- uwsgi_buffer_sizelocation /news {
uwsgi_pass mobs_backend;include uwsgi_params;uwsgi_buffers 256 16k;
}
16
Профилирование django-python
Профилирование начинается в голове разработчика ©http://bit.ly/2cV82Gg http://bit.ly/2ckeTKS
pip install django-extensionsINSTALLED_APPS += ('django_extensions',)python manage.py runprofileserver --use-cprofile --prof-path=~/profwget -O- -S http://127.0.0.1:8000/news/v2/getNewsById?id=291235 gprof2dot -f pstats ~/prof/out.prof | dot -Tpng -o ~/prof/out.png
17
Визуализация результатов профилирования
18
Визуализация результатов профилирования
19
Тюнинг memcached
- python-memcached pickle/cpickle commit http://bit.ly/2ckfdJL
- модуль pymemcache http://bit.ly/2cDCsir
- упаковка/распаковка через msgpack
- использование опций noreply=true, tcp_nodelay=120
К чему мы стремимся при разработке backend
- Меньше обращений
- Легкие запросы
- Простые решения
21
Подводим итоги
- Разработка backend для мобильных приложений отличается от backend для web приложений
- Производительность стека python – django – uwsgi – nginx требует экспериментальных проверок в продакшен
- Для мобильного приложения очень важно время ответа backend
- Время ответа backend нужно измерять правильно
22
Настройка mysql
- myISAM, не используем транзакции- key_buffer_size >= sum(du -hs *.MYI)- ssd- mysql_query_cache- mysql_slow_query_log
24
Пример кода view, чего стараемся избегать
class GetNewsByIdView(BaseNewsView):
def get_response(self, request):
if version == "1.0":
return {...}
elif version == "2.0":
return []
25