"Микросервисы и Nameko" Практика микросервисов Python

Микросервисы
"Микросервисы и Nameko" Практика микросервисов Python

1. Microservices

Микросервисы были очень популярны и о них много говорили в последние год или два.Короче говоря, микросервисы — это способ разработки одного приложения в виде набора, состоящего из множества небольших сервисов, каждый из которых имеет свой собственный процесс и использует облегченный механизм. (обычно API источника HTTP) обеспечивает связь. Вот пример изображения:

Microservices Architecture:

Две приведенные выше картинки уже показали, что такое микросервис, и метод развертывания программного обеспечения должен быть построен на контейнере. Экосистема, связанная с микросервисами, будет более зрелой на языках Java и Go, особенно на Java. Python как серверная часть слабее в этом аспекте.Среда микросервисов может видеть только Nameko, а технология не настолько зрелая.Поскольку текущая сцена Python для бизнеса немного больше, чем язык Go, давайте сначала поиграем с Python.Микросервисы.

2. Service Mesh and Serverless

Что касается микросервисов, то есть еще две популярные концепции, кратко упомянутые ниже.

2.1 Service Mesh

Концепция сервисной сетки Service Mesh поначалу неясна, и некоторые люди в Интернете также говорят о следующем поколении микросервисов.Проще говоря, когда тысячи микросервисов развернуты в Kubernetes, все становится довольно сложным, потому что каждый микросервис требуется проверка работоспособности, обработка ошибок, задержка и т. д. Хотя Kubernetes может обеспечивать проверку работоспособности и автоматическое восстановление, ему также требуется режим прерывателя цепи, обнаружение служб, управление API, проверка шифрования и т. д. Именно эти проблемы необходимо решить Service Mesh.

Более подробное введение:Фил Кальк ADO.com/2017/08/03/…

В качестве инфраструктурного уровня сервисной связи его можно сравнить с приложением или микросервисом TCP/IP, отвечающим за сетевые вызовы, текущие ограничения, предохранитель и мониторинг между сервисами. Для написанных приложений нет необходимости заботиться о TCP / IP (например, приложения RESTful через протокол HTTP), а сервисная сетка используется для достижения целей между приложениями или другими фреймворками.Например, Spring Cloud, теперь просто передайте его сервисная сетка.

Service Mesh имеет следующие характеристики:

  • Средний уровень связи между приложениями
  • Легкий веб-прокси
  • приложение-агностик
  • Раздельные повторные попытки/тайм-ауты приложений, мониторинг, отслеживание и обнаружение служб

Архитектура Service Mesh показана на следующем рисунке:

Более популярным программным обеспечением с открытым исходным кодом является Istio, и у меня есть возможность поиграть в него снова.

2.2 Serverless

Архитектура без сервеса, сначала связалась с саммитом технологии AWS, просто означает, что нет необходимости ухода за серверами, и весь вычислительный стек, включая процессы операционной системы, запускающие функциональный код, полностью управляются облачным провайдером. Это еще больше укрепляет концепцию дежобов.

На самом деле я играл в бессерверное приложение AWS Lambda, оно действительно удобно, оно упрощено до функции, а веб-сервисы можно реализовать через API Gateway + Lambda. Взимать плату в зависимости от количества запросов в настоящее время очень жалко, особенно когда количество запросов велико, стоимость намного дороже, чем развертывание приложения на Docker самостоятельно. Таким образом, текущий сценарий бессерверной архитектуры также очень подходит для некоторых разовых задач и очень удобен для сценариев с небольшим количеством запросов, участники-разработчики могут разработать собственное развертывание и больше не нужно заботиться о сервере. . Все операции по эксплуатации и техническому обслуживанию могут быть устранены, а разработчики могут больше сосредоточиться на развитии основного бизнеса, что обеспечивает быстрый запуск и итерацию.

3. Python framework for building microservices

3.1 Nameko Introduce

Nameko — микросервисный фреймворк на Python, находится по адресу https://github.com/nameko/nameko на git, популярность пока невысока, реализовано внедрение официальных документов:

It comes with built-in support for:

  • RPC over AMQP
  • Asynchronous events (pub-sub) over AMQP
  • Simple HTTP GET and POST
  • Websocket RPC and subscriptions (experimental)

Проще говоря, RPC построен на AMQP, который реализует публикацию и подписку на AMQP, реализует простые службы HTTP и Websocket RPC.

Это совершенно Педиатрический с экологией Явы. Архитектура использует RabbitMQ в качестве брокера сообщений для обеспечения связи между каждой службой Nameko.

Ознакомьтесь с официальной документацией для более подробной информации.

3.2 Practice

Далее потренируемся на примере бизнес-сценария.

Сцены:Предположим, что в социальном сценарии при комментировании чужой статьи сервер отправляет сообщение автору статьи, чтобы уведомить кого-то о необходимости комментировать, и сначала этот комментарий должен быть зарегистрирован.

Включает в себя 2 микросервиса, сервис регистрации и сервис push, и в то же время имеет интерфейс комментариев.

3.2.1 Окружающая среда Строительство:

  • python3.5+
  • RabbitMQ
  • Redis 3.2.1
  • Nameko 2.11.0
  • Swagger
  • Flask 1.0.2

Во-первых, вам нужно подготовить среду Python 3. Для простоты в качестве хранилища для входа и регистрации пользователей используется Redis, Nameko устанавливается с помощью pip, а RabbitMQ лучше всего устанавливать с Docker.

# RabbitMQ docker 安装命令
docker search rabbitmq
docker pull rabbitmq:3.7-rc-management
docker run -d --hostname my-rabbit --name some-rabbit -p 15672:15672 -p 5672:5672 rabbitmq:3.7-rc-management
# 需要默认运行在5672端口

Doc: https://github.com/docker-library/docs/tree/master/rabbitmq

# nameko 运行服务命令:
nameko run service --broker amqp://guest:guest@localhost

其中 guest:guest是RabbitMQ Docker镜像的用户名和密码

В то же время, чтобы облегчить тестирование API, пользовательский интерфейс Swagger предоставляется через Flasgger для интеграции Flask.

Когда вы готовые среды, начните раздел кода.

3.2.2 код демонстрирует:

├── app
│   └── api.py
├── dependence
│   ├── __init__.py
│   └── services
│       ├── __init__.py
│       ├── config.py
│       └── redis_service.py
└── microservices
    ├── push.py
    └── register.py

Структура кода такая же, как указано выше:

  • Служба интерфейса API хранится в приложении.
  • зависимость можно понимать как базовый модуль.Многие микросервисы могут зависеть от пакетных сервисов, таких как интерфейсы redis и mysql.Как правило, если вы используете репозиторий Git, вы можете подмодулить к репозиторию конкретного сервиса.Здесь размещаются все тесты в одном репозитории.
  • microservices Код микросервиса, здесь 2 сервиса, регистрация и пуш.

Есть 2 функции, которые нужно практиковать:

  • Как вызывать микросервисы в коде API
  • Как вызывать другие микросервисы в микросервисах

Давайте сначала представим код в зависимости:

# content of redis_service
class RedisService(object):
    def __init__(self):
        self.redis_instance = RedisClient.get_redis(
            config.REDIS_NAME, config.REDIS_HOST, config.REDIS_PORT,
            config.REDIS_DB)
        self.users_key = "users"
        self.users_data_key = "users_data"

    def check_registered_and_get_info(self, u_id):
        """
        Check if the user is registered and return user information if registered.
        """
        user_data = self.redis_instance.hget(self.users_data_key, u_id)
        if not user_data:
            return False, None
        return True, json.loads(user_data)

    def check_email_is_registered(self, email):
        u_id = self.redis_instance.hget(self.users_key, email)
        return u_id

    def register(self, u_id, email, data):
        self.redis_instance.hset(self.users_key, email, u_id)
        result = self.redis_instance.hset(self.users_data_key, u_id,json.dumps(data))
        return result
  • check_registered_and_get_info Проверить, был ли он зарегистрирован, если он был зарегистрирован, получить информацию о пользователе и вернуться
  • check_email_is_registered Проверить, зарегистрирован ли адрес электронной почты дважды
  • зарегистрируйтесь, чтобы зарегистрироваться и сохранить информацию о пользователе

Затем посмотрите на часть кода API:

# content of api.py
import time
import random
from flask import Flask, request, jsonify
from flasgger import Swagger
from nameko.standalone.rpc import ClusterRpcProxy
import argparse

parser = argparse.ArgumentParser()
parser.add_argument("--port", help="app running port", type=int, default=5000)
parse_args = parser.parse_args()

app = Flask(__name__)
Swagger(app)

CONFIG = {'AMQP_URI': "amqp://guest:guest@localhost"}

Принципал кода отображается отдельно. Эта часть является справочной частью. Nameko и Swagger требуется. Nameko - агент службы RPC, который предоставляет микросервисы. В то же время необходимо предоставить конфигурацию. Содержание является адресом Сообщение брокер, который на самом деле rabbitmq. SWARGER сочетается с колбой, чтобы облегчить тестирование API на веб-интерфейсе.

# content of api.py
@app.route('/api/v1/comment', methods=['POST'])
def comment():
    """
    Comment API

    Parameters Explain:

        timestamp    评论时间
        u_id         用户id
        content      评论内容
        article_id   文章ID
        article_u_id 文章作者用户id
        parent_comment_id 父评论id (optional)
    ---
    parameters:
      - name: body
        in: body
        required: true
        schema:
          id: comment
          properties:
            timestamp:
              type: integer
            u_id:
              type: string
            content:
              type: string
            article_id:
              type: integer
            article_u_id:
              type: integer
            parent_comment_id:
              type: integer
    responses:
      code:
        description: 0 Comment Success!
      message:
        description: Error Message!
      data:
        description: return comment_id
    """
    data = request.json
    article_u_id = data.get("article_u_id")
    u_id = data.get("u_id")
    code, message = 0, ""
    if not article_u_id or not u_id:
        code, message = 10003, "article_u_id or u_id is null."
        response = dict(code=code, message=message, data="")
        return jsonify(response)
    with ClusterRpcProxy(CONFIG) as rpc:
        user_data = rpc.register.check_registered(u_id)
        if not user_data:
            code, message = 10004, "You need to register to comment."
            response = dict(code=code, message=message, data="")
            return jsonify(response)

        # push message
        print("Push Message: article_u_id: {}".format(article_u_id))
        result, message = rpc.push.push(article_u_id, data.get("content"))
        print("push result: {}, message: {}".format(result, message))

    # save comment data
    print("Save Comment Data: article_id: {} content: {}".format(
        data.get("article_id"), data.get("content")))

    data = dict(comment_id=int(time.time()))
    response = dict(code=0, message="", data=data)
    return jsonify(response)

Интерфейс комментариев, часть описания - предоставить описание интерфейса API Swagger (спецификация должна следовать спецификации SWARGER, вы можете проверить официальный документ для получения подробной информации), предоставить идентификатор пользователя комментариев, идентификатор статьи, содержание комментария, И идентификатор пользователя автора статьи (для простоты, непосредственно предоставленного клиентом, обычный сценарий - найти идентификатор пользователя автора на основе идентификатора статьи).

Функция реализована также очень просто.Сначала проверьте службу регистрации, позвонив, чтобы узнать, зарегистрировался ли комментатор.Если нет, он сразу вернется к необходимости зарегистрироваться для комментирования. Если он был зарегистрирован, вызывается push-сервис для отправки push-уведомлений автору. После этого и сохраните информацию о комментарии, верните идентификатор комментария.

Ключевая информация — зарегистрироваться и запустить реализацию микросервиса, а также сохранить информацию о комментариях. Я печатаю ее прямо здесь, не выполняя никаких реальных операций.

@app.route('/api/v1/register', methods=['POST'])
def register():
    """
    Register API

    Parameters Explain:

        timestamp    注册时间
        email        注册邮箱
        name         名称
        language     语言
        country      国家
    ---
    parameters:
      - name: body
        in: body
        required: true
        schema:
          id: data
          properties:
            timestamp:
              type: integer
            email:
              type: string
            name:
              type: string
            language:
              type: string
            country:
              type: string
    responses:
      code:
        description: 0 register success.
      message:
        description: Error Message!
      data:
          description: return u_id
    """

    user_data = request.json
    email = user_data.get("email")
    code, message = 0, ""
    if not email:
        code, message = 10000, "email is null."
        response = dict(code=code, message=message, data="")
        return jsonify(response)
    u_id = None
    with ClusterRpcProxy(CONFIG) as rpc:
        u_id, message = rpc.register.register(email, user_data)
    if message:
        code = 10001
    data = dict(u_id=u_id)
    response = dict(code=code, message=message, data=data)
    return jsonify(response)


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=int(parse_args.port), debug=True)

Это последний раздел api.py, который реализует интерфейс регистрации. Короче говоря, он вызывает службу регистрации. Если он был зарегистрирован, он возвращается напрямую, в противном случае он сохраняет информацию о пользователе.

Ключ заключается в реализации службы регистрации.

бегатьpython api.pyОткрытымhttp://localhost:5000/apidocs/Вы можете увидеть следующий интерфейс:

Нажмите на один из API, вы увидите следующий интерфейс:

Очень удобно отлаживать интерфейс API.

Следующий момент — продемонстрировать часть кода микросервиса:

import random
from nameko.rpc import rpc
import sys
sys.path.append("..")
from dependence.services import RedisService

class RegisterService(object):
    name = "register"

    def __init__(self):
        self.redis_handle = RedisService()

    @rpc
    def check_registered(self, u_id):
        is_registered, user_data =   self.redis_handle.check_registered_and_get_info(u_id)
        if is_registered:
            return user_data
        return None

    @staticmethod
    def generate_u_id():
        """
        Test Function
        """
        return str(random.randint(7000000, 9999999))

    @rpc
    def register(self, email, user_data):
        u_id = self.redis_handle.check_email_is_registered(email)
        if u_id:
            return u_id, "already registered."
        u_id = self.generate_u_id()
        register_result = self.redis_handle.register(u_id, email, user_data)
        if register_result:
            return u_id, ""
        return None, "register failed.

Обратите внимание на реализацию register, вам нужно импортировать nameko.rpc, и украсить функцию rpc. Реализация очень простая, код внутри это логическая часть, которая генерирует u_id и сохраняет его в redis.

Таким образом реализуется первая функция, вызывающая микросервис в API.

Далее посмотрите на реализацию Push-сервиса:

import random
from nameko.rpc import rpc, RpcProxy
import sys
sys.path.append("..")
from dependence.services import RedisService

class PushService(object):
    name = "push"
    register_rpc = RpcProxy("register")

    @rpc
    def push(self, u_id, content):
        user_data = self.register_rpc.check_registered(u_id)
        if not user_data:
        print("User:{} not existed.".format(u_id))
            return False, "not registered."
        language, country = user_data["language"], user_data["country"]

        # get language push content
        print("Push Progress: u_id: {} language: {}, country: {}, content: {}".
              format(u_id, language, country, content))

        return True, "push success."

В push-сервисе необходимо вызвать службу регистрации, чтобы определить, зарегистрирован ли автор статьи (на самом деле, он должен быть зарегистрирован, чтобы иметь возможность опубликовать статью, которая ссылается на демо здесь). , для вызова микросервиса в микросервисе требуется дополнительный импорт RpcProxy, и сервис регистрации RpcProxy("register"), а потом вызывать его в сервисе, и получать информацию о пользователе, судить о языке и стране, и пушить соответствующий языковое содержание.

В целом, структура Nameko, реализация уровня кода очень проста, легка, проста и практична. Тем не менее, функции не завершены, и сценариев для серверных приложений Python не так много.

3.2.3 Отладка

开三个终端,分别运行:

cd microservices & nameko run push
cd microservices & nameko run register

cd app & python api.py

Открытымhttp://localhost:5000/apidocs/#/

Подготовьте регистрационные данные:

注册信息1
{
  "country": "CN",
  "email": "nameko@nameko.com",
  "language": "ZH",
  "name": "xiaohua",
  "timestamp": 1553652949
}

注册信息2
{
  "country": "CN",
  "email": "nameko2@nameko.com",
  "language": "ZH",
  "name": "xiaoming",
  "timestamp": 1553652950
}

Пример операции:

Возвращенные сообщения:

返回信息1
{
  "code": 0,
  "data": {
    "u_id": "7434029"
  },
  "message": ""
}

返回信息2
{
  "code": 0,
  "data": {
    "u_id": "8240184"
  },
  "message": ""
}

Вызов push-интерфейса:

Нажмите, чтобы выполнить.

возвращенные сообщения:

информация о печати терминала python api.py:

Push Message: article_u_id: 7434029
push result: True, message: push success.
Save Comment Data: article_id: 100 content: very good.
127.0.0.1 - - [27/Mar/2019 23:24:07] "POST /api/v1/comment HTTP/1.1" 200 -

Здесь демонстрируется микросервис Python, полный код github addressGitHub.com/Хрустальное небо Z…

Далее поговорим о RPC.

Для получения более интересных статей, пожалуйста, обратите внимание на публичный аккаунт «Tiancheng Technology Talk».