Neurohazard
暮雲煙月,皓首窮經;森羅萬象,如是我聞。

Nameko 关键概念梳理

wpadmin~October 11, 2019 /Software Engineering

Nameko 关键概念梳理

服务的定义 (Anatomy of a Service)

一个 Nameko 服务就是 一个 Python 类 (class)。该类将应用程序逻辑封装在其方法中,并将所有依赖项声明为类的属性。
方法通过入口装饰器 (entrypoint decorators) 暴露给外界。

from nameko.rpc import rpc, RpcProxy

class Service:
    name = "service"

    # we depend on the RPC interface of "another_service"
    other_rpc = RpcProxy("another_service")

    @rpc  # `method` is exposed over RPC
    def method(self):
        # application logic goes here
        pass

入口点 (Entrypoints)

入口点是通向它们装饰的服务方法的网关。它们通常监视外部实体,例如消息队列。在相关事件上,入口点可能会触发 (fire) ,并且修饰的方法将由服务工作程序(service worker)执行。

依赖 (Dependencies)

大多数服务都依赖于自己以外的东西。Nameko 鼓励将这些东西实现为依赖项。

依赖关系是隐藏不属于核心服务逻辑的代码的机会。服务的依赖项接口应尽可能简单。

出于多种原因,在服务中声明依赖关系是一个好主意,您应该将它们视为服务代码与其他所有内容之间的网关。这包括其他服务,外部 API 甚至数据库。

工作程序 (Worker)

此处的 worker 是指 Master-Worker 设计模式中的 worker 。

入口点触发 (fire) 时会创建 工作程序 (worker) 。 工作程序 (worker) 只是服务类 (service class) 的一个实例,但是依赖项声明已替换为那些依赖项的实例(请参阅依赖项注入)。

请注意,工作程序 (worker) 的生命周期只在于一个方法的执行。服务从一个调用到下一个调用都是无状态的,这鼓励了依赖的使用。

一个服务可以同时运行多个工作程序,最多可以达到用户定义的限制。有关详细信息,请参见并发 (concurrency) 章节。

依赖注入 (Dependency Injection)

向服务类添加依赖项是声明性的。也就是说,类上的属性是声明,而不是工人可以实际使用的接口。

class 属性是 DependencyProvider。它负责提供注入服务人员的对象。

依赖关系提供程序实现一种 get_dependency() 方法,其结果被注入到新创建的工作程序中。

工作程序的生命周期为:

1 入口触发
2 从服务类实例化的工作程序
3 依赖注入工作程序
4 方法执行
5 工作程序被摧毁

伪代码为

worker = Service()
worker.other_rpc = worker.other_rpc.get_dependency()
worker.method()
del worker

DependencyProvider 在 整个服务的生命周期内 有效,而注入的依赖关系对于每个工作程序而言都是唯一的。

并发 (Concurrency)

Nameko 建立在 eventlet 库之上,该库通过 “greenthreads” 提供并发性。并发模型是具有隐式屈服的协同例程。

隐式良率依赖于猴子修补标准库,以在线程等待 I/O 时触发良率。如果您在命令行上使用托管服务,Nameko 将为您应用 Monkey 补丁。 nameko run

每个工作程序都在其自己的 greenthread 中执行。可以根据每个工人在 I/O 上等待所花费的时间来调整并发工人的最大数量。

工作进程是无状态的,因此线程固有的安全性,但是依赖关系应确保它们对于每个工作进程都是唯一的,否则,可以安全地由多个工作进程同时访问。

请注意,许多正在使用套接字的C扩展名(通常被认为是线程安全的)可能不适用于 greenthreads。其中有 librabbitmq, MySQLdb 等。

扩展 (Extensions)

所有入口点和依赖项提供程序都实现为“扩展”。我们之所以这样称呼它们,是因为它们在服务代码之外,但并非所有服务都必需(例如,纯AMQP公开的服务将不使用HTTP入口点)。

Nameko 有许多内置扩展,一些由社区提供,您可以编写自己的扩展。

运行服务 (Running Services)

运行服务所需要做的就是服务类和任何相关配置。运行一项或多项服务的最简单方法是使用Nameko CLI:

$ nameko run module:[ServiceClass]

此命令将在给定 modules 中发现 Nameko 服务并开始运行它们。您可以选择将其限制为特定的 ServiceClass

服务容器 (Service Containers)

每个服务类都委托给一个 ServiceContainer。该容器封装了运行服务所需的所有功能,并且还封装了服务类的所有扩展。

使用 ServiceContainer 来运行单个服务:

from nameko.containers import ServiceContainer

class Service:
    name = "service"

# create a container
container = ServiceContainer(Service, config={})

# ``container.extensions`` exposes all extensions used by the service
service_extensions = list(container.extensions)

# start service
container.start()

# stop service
container.stop()

服务运行器 (Service Runner)

ServiceRunner是围绕多个容器的薄包装,公开了同时启动和停止所有包装容器的方法。这是 nameko run 内部使用的内容,也可以通过编程方式构造:

from nameko.runners import ServiceRunner
from nameko.testing.utils import get_container

class ServiceA:
    name = "service_a"

class ServiceB:
    name = "service_b"

# create a runner for ServiceA and ServiceB
runner = ServiceRunner(config={})
runner.add_service(ServiceA)
runner.add_service(ServiceB)

# ``get_container`` will return the container for a particular service
container_a = get_container(runner, ServiceA)

# start both services
runner.start()

# stop both services
runner.stop()

如果创建自己的运行程序而不是使用 nameko run,则还必须应用eventlet 猴子补丁。

有关示例,请参见 nameko.cli.run 模块。

Leave a Reply

Your email address will not be published. Required fields are marked *