关键概念¶
本节介绍 Nameko 的核心概念。
服务结构¶
Nameko 服务只是一个 Python 类。类的方法封装了应用程序逻辑,并将任何 依赖项 声明为属性。
通过 入口点 装饰器,方法向外界公开。
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
入口点¶
入口点是服务方法的访问通道。它们通常监控外部实体,例如消息队列。当相关事件发生时,入口点可能会“触发”,然后由服务 worker 执行被装饰的方法。
依赖项¶
大多数服务依赖于自身以外的事物。Nameko 鼓励将这些事物实现为依赖项。
依赖项是隐藏不属于核心服务逻辑的代码的好机会。依赖项与服务的接口应尽可能简单。
在服务中声明依赖项是一个好主意,原因有很多 好处,你应该将其视为服务代码与其他所有内容之间的桥梁。这包括其他服务、外部 API,甚至是数据库。
Worker¶
当入口点触发时,会创建一个 worker。worker 只是服务类的一个实例,但依赖声明会被替换为这些依赖的实例(参见 依赖注入 )。
需要注意的是,worker 只在执行一个方法时存在——服务在每次调用之间是无状态的,这鼓励使用依赖项。
一个服务可以同时运行多个 worker,数量上限由用户定义。详细信息请参见 并发 。
依赖注入¶
向服务类添加依赖项是声明式的。也就是说,类上的属性是一个声明,而不是 workers 实际可以使用的接口。
该类属性是一个 DependencyProvider
。它负责提供一个被注入到服务 worker 中的对象。
依赖提供者实现了一个 get_dependency()
方法,其结果被注入到新创建的 worker 中。
worker 的生命周期如下:
入口点触发
从服务类实例化 worker
依赖项注入到 worker 中
方法执行
worker 被销毁
在伪代码中,这看起来像这样:
worker = Service()
worker.other_rpc = worker.other_rpc.get_dependency()
worker.method()
del worker
依赖提供者在服务的整个生命周期内存在,而注入的依赖项可以是每个 worker 唯一的。
并发¶
Nameko 建立在 eventlet 库之上,该库通过“绿色线程”提供并发。并发模型是带有隐式让渡的协程。
隐式让渡依赖于对标准库进行 猴子补丁,以在线程等待 I/O 时触发让渡。如果您通过命令行使用 nameko run
托管服务,Nameko 将为您应用猴子补丁。
每个 worker 在自己的绿色线程中执行。可以根据每个 worker 等待 I/O 的时间调整最大并发 worker 数量。
worker 是无状态的,因此本质上是线程安全的,但依赖项应确保它们在每个 worker 中是唯一的,或者可以安全地被多个 worker 并发访问。
请注意,许多使用套接字的 C 扩展,通常被认为是线程安全的,可能与绿色线程不兼容。其中包括 librabbitmq 、 MySQLdb 等。
扩展¶
所有入口点和依赖提供者都被实现为“扩展”。我们这样称呼它们,因为它们在服务代码之外,但并不是所有服务都需要(例如,一个完全暴露于 AMQP 的服务不会使用 HTTP 入口点)。
运行服务(Running Services)¶
运行服务所需的仅仅是服务类和任何相关的配置。运行一个或多个服务的最简单方法是使用 Nameko CLI:
$ nameko run module:[ServiceClass]
此命令将发现给定 module
s 中的 Nameko 服务并开始运行它们。您可以选择将其限制为特定的 ServiceClass
s 。
服务容器(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 的 monkey patch 。
有关示例,请参见 nameko.cli.run
模块。