Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Монолит + микросервисы = любовь

Монолит + микросервисы = любовь

Максим Филипенко (Marilyn, разработчик) @ Moscow Python Meetup 57
"Рассказ о том, как мы внедряли сервисную архитектуру в монолитный B2B-проект. Чем это было хорошо, чем это было плохо, как поменялся наш workflow".

Видео: http://www.moscowpython.ru/meetup/57/monolith-microservices-love/

Moscow Python Meetup
PRO

June 26, 2018
Tweet

More Decks by Moscow Python Meetup

Other Decks in Programming

Transcript

  1. МОНОЛИТ + МИКРОСЕРВИСЫ = ❤
    Филипенко Максим

    View Slide

  2. mymarilyn.ru

    View Slide

  3. Что было

    View Slide

  4. View Slide

  5. Просто

    View Slide

  6. Зачем менять?

    View Slide

  7. Проблемы монолитов

    View Slide

  8. • Кодовая база растет, её становится сложнее тестировать и
    поддерживать
    Проблемы монолитов

    View Slide

  9. • Кодовая база растет, её становится сложнее тестировать и
    поддерживать
    • Связность между модулями может вызывать неожиданные баги
    Проблемы монолитов

    View Slide

  10. • Кодовая база растет, её становится сложнее тестировать и
    поддерживать
    • Связность между модулями может вызывать неожиданные баги
    • Новым разработчикам сложно разобраться с проектом
    Проблемы монолитов

    View Slide

  11. • Кодовая база растет, её становится сложнее тестировать и
    поддерживать
    • Связность между модулями может вызывать неожиданные баги
    • Новым разработчикам сложно разобраться с проектом
    • Выкатка занимает много времени (тесты!)
    Проблемы монолитов

    View Slide

  12. • Кодовая база растет, её становится сложнее тестировать и
    поддерживать
    • Связность между модулями может вызывать неожиданные баги
    • Новым разработчикам сложно разобраться с проектом
    • Выкатка занимает много времени (тесты!)
    • Сложно обновляться и использовать новые технологии
    Проблемы монолитов

    View Slide

  13. Python 2.7

    View Slide

  14. Python 2.7

    View Slide

  15. И всё?

    View Slide

  16. Неразрешимые проблемы

    View Slide

  17. • Переиспользование общей логики между командами с разным
    стеком
    Неразрешимые проблемы

    View Slide

  18. • Переиспользование общей логики между командами с разным
    стеком
    • Использование несовместимых технологий
    Неразрешимые проблемы

    View Slide

  19. Что мы стали использовать

    View Slide

  20. Python 3.6+

    View Slide

  21. Внутренние пакеты

    View Slide

  22. • Где хранить
    Внутренние пакеты

    View Slide

  23. • Где хранить
    • Как именовать
    Внутренние пакеты

    View Slide

  24. • Где хранить
    • Как именовать
    • В каком случае нужно создавать
    Внутренние пакеты

    View Slide

  25. • Где хранить
    • Как именовать
    • В каком случае нужно создавать
    • Версионирование
    Внутренние пакеты

    View Slide

  26. • Где хранить
    • Как именовать
    • В каком случае нужно создавать
    • Версионирование
    • Changelog изменений
    Внутренние пакеты

    View Slide

  27. deploy_pypi:
    stage: deploy
    only:
    - master
    script:

    - echo "repository="$PYPI_REPO_URL >> ~/.pypirc
    - echo "username="$PYPI_USER >> ~/.pypirc
    - echo "password="$PYPI_PASSWORD >> ~/.pypirc
    - python3 setup.py sdist bdist_wheel upload -r pypi-internal
    Внутренние пакеты
    Тестируются и загружаются в локальный PyPI через Gitlab CI

    View Slide

  28. Docker

    View Slide

  29. Docker-compose

    View Slide

  30. services:
    app:
    image: development
    build:
    context: .
    dockerfile: ./docker/development/Dockerfile
    depends_on:
    - base
    links:
    - postgres
    - redis
    environment:
    - REDIS_URI=redis://redis:6379/0
    ports:
    - "5000:80"
    command: flask run --host=0.0.0.0 --port=80
    postgres:
    image: postgres:10.0
    ports:
    - "55432:5432"
    redis:
    ...

    View Slide

  31. $ git clone path-to-git-repo
    $ cd path-to-git-repo
    $ docker-compose up
    ...
    app_1 | Running command: flask run --host=0.0.0.0 --port=80
    app_1 | * Running on http://0.0.0.0:80/ (Press CTRL+C to quit)
    app_1 | * Restarting with stat
    app_1 | * Debugger is active!
    Начало работы над проектом

    View Slide

  32. Swagger

    View Slide

  33. View Slide

  34. Взаимодействие между сервисами

    View Slide

  35. • HTTP JSON API
    Взаимодействие между сервисами

    View Slide

  36. • HTTP JSON API
    • RESTful
    Взаимодействие между сервисами

    View Slide

  37. • HTTP JSON API
    • RESTful
    • JWT
    Взаимодействие между сервисами

    View Slide

  38. Gitlab

    View Slide

  39. Gitlab CI или Jenkins?

    View Slide

  40. stages:
    - build
    - test
    - cleanup
    - publish

    test:
    stage: test
    script:
    - '$DOCKER_COMPOSE run app py.test -p no:cacheprovider’
    publish master:
    stage: publish
    only:
    - master
    script:
    - 'docker build -f docker/base/Dockerfile -t $CI_REGISTRY_IMAGE/base-master .'
    ...
    - 'docker push $CI_REGISTRY_IMAGE/base-master'
    ...

    View Slide

  41. Kubernetes

    View Slide

  42. Тестирование
    Pytest + FactoryBoy

    View Slide

  43. 100% code coverage

    View Slide

  44. Тестирование: проблемы

    View Slide

  45. • Тестировать – сложно
    Тестирование: проблемы

    View Slide

  46. • Тестировать – сложно
    • Написать хороший тест – еще сложнее
    Тестирование: проблемы

    View Slide

  47. • Тестировать – сложно
    • Написать хороший тест – еще сложнее
    • 100% code coverage не гарантирует НИЧЕГО (особенно когда есть
    внешние API)
    Тестирование: проблемы

    View Slide

  48. • Тестировать – сложно
    • Написать хороший тест – еще сложнее
    • 100% code coverage не гарантирует НИЧЕГО (особенно когда есть
    внешние API)
    • Сложная логика между сущностями
    Тестирование: проблемы

    View Slide

  49. Тестирование: решение

    View Slide

  50. • Не пытаться протестировать все возможные ответы площадок
    Тестирование: решение

    View Slide

  51. • Не пытаться протестировать все возможные ответы площадок
    • На каждый endpoint должны быть тесты
    Тестирование: решение

    View Slide

  52. • Не пытаться протестировать все возможные ответы площадок
    • На каждый endpoint должны быть тесты
    • Для имитации сетевого взаимодействия использовать mock и
    responses
    Тестирование: решение

    View Slide

  53. • Не пытаться протестировать все возможные ответы площадок
    • На каждый endpoint должны быть тесты
    • Для имитации сетевого взаимодействия использовать mock и
    responses
    • Декларативное создание сущностей (FactoryBoy)
    Тестирование: решение

    View Slide

  54. • Не пытаться протестировать все возможные ответы площадок
    • На каждый endpoint должны быть тесты
    • Для имитации сетевого взаимодействия использовать mock и
    responses
    • Декларативное создание сущностей (FactoryBoy)
    Тестирование: решение

    View Slide

  55. @pytest.fixture(scope="session")
    def session(db_fixture):
    db_fixture.session.begin()
    yield db_fixture.session
    db_fixture.session.remove()
    @pytest.fixture(scope="function")
    def transaction(session):
    session.begin(nested=True)
    try:
    yield session
    finally:
    session.rollback()
    @pytest.fixture(scope=“function")
    def mock_contextmanager(session):
    with patch('src.yourmodule.contextmanager') as mocked:
    mocked_context = MagicMock()
    mocked_context.__enter__.return_value = session
    mocked.return_value = mocked_context
    yield mocked

    View Slide

  56. Новая функциональность:
    ⦿ монолит?
    ⦿ а может быть микросервис?

    View Slide

  57. Когда НЕ НУЖНО заводить
    микросервис

    View Slide

  58. • Нет понимания, что должен делать сервис
    Когда НЕ НУЖНО заводить
    микросервис

    View Slide

  59. • Нет понимания, что должен делать сервис
    • Вынесение должно быть обоснованным
    Когда НЕ НУЖНО заводить
    микросервис

    View Slide

  60. • Нет понимания, что должен делать сервис
    • Вынесение должно быть обоснованным
    • Если нужен простой CRUD
    Когда НЕ НУЖНО заводить
    микросервис

    View Slide

  61. Что получилось

    View Slide

  62. View Slide

  63. Сложно

    View Slide

  64. Стало ли хуже?

    View Slide

  65. Минусы

    View Slide

  66. • Связи между сервисами накладывают определенную сложность
    Минусы

    View Slide

  67. • Связи между сервисами накладывают определенную сложность
    • Сложность и особенности предметной области никуда не делись
    Минусы

    View Slide

  68. • Связи между сервисами накладывают определенную сложность
    • Сложность и особенности предметной области никуда не делись
    • Тулинг пока отстает
    Минусы

    View Slide

  69. • Связи между сервисами накладывают определенную сложность
    • Сложность и особенности предметной области никуда не делись
    • Тулинг пока отстает
    • Администрирование стало сложнее
    Минусы

    View Slide

  70. Плюсы

    View Slide

  71. • Удалось добиться переиспользования логики между командами
    Плюсы

    View Slide

  72. • Удалось добиться переиспользования логики между командами
    • Можно работать над задачами не вникая в старый код
    Плюсы

    View Slide

  73. • Удалось добиться переиспользования логики между командами
    • Можно работать над задачами не вникая в старый код
    • Можно быстро вносить и выкатывать изменения
    Плюсы

    View Slide

  74. • Удалось добиться переиспользования логики между командами
    • Можно работать над задачами не вникая в старый код
    • Можно быстро вносить и выкатывать изменения
    • Легко подбирать подходящий инструмент под конкретную задачу
    Плюсы

    View Slide

  75. View Slide

  76. prokaktus
    prokaktus
    [email protected]
    Филипенко Максим

    View Slide

  77. Спасибо!

    View Slide