Contents
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