python微服务框架nameko解读

3,609 阅读5分钟

nameko说明

nameko作为微服务框架,没有服务治理模块,类似的功能交给了rabbitmq(基于AMQP的中间件)处理。 Nameko是一个异步消息传递系统,实现了发布订阅模式。服务分派事件,这些事件可能被零个或更多的其他人接收

nameko启动服务过程

1.将rpc服务添加到service_runner
2.SpawningProxy类主要用来进行eventlet相关的调用,它先生产一个GreenPool(初始化大小=max_workers),然后遍历所有的ServiceContainers对象,针对每个对象调用start函数,运行在一个green thread中
3.服务start完后,eventlet调用了spawn函数,参数是service_runner.wait,我们打印一下这个参数,是ServiceRunner类的wait函数,接着这个函数在while循环中被调用,服务启动完成处于待命状态

系统处理时序图

image

核心点说明

Service

在nameko中,Service就是服务,对应到代码中就是一个Python类,每个类有个name属性表示这个类所对应服务的名称,并通过成员函数封装应用逻辑,以类属性形式声明应用逻辑需要依赖的其他服务,同时通过入口点(EntryPoint)修饰器将接口暴露出来供其它服务调用。

EntryPoints

EntryPoints即入口点,是它所修饰的函数的网关,它一般监听一些外部实体,如消息队列。当收到对应的消息时,入口点被触发,其所修饰函数就会在Worker中被执行。

Dependencies

Dependencies即依赖者,因为拆分成微服务以后,很多服务都是需要调用其他服务的功能来完成某项业务,而其他服务协助完成的功能又不是本服务核心业务逻辑的一部分,这时候就将这部分非核心业务功能抽出来写成Dependency的形式,如果有另外一些服务也需要以依赖者的形式使用该Dependency,Dependency的代码就得到了复用,而不需要每个服务都去实现一遍类似于这个Dependency的功能。和EntryPoints类似,Dependencies也可以看作是网关,它是本服务与其他外部实体(如其他服务,外部API等)之间的网关。

Workers

Workers即工作者,是当一个EntryPoints触发时被创建。一个工作者就是Service类的一个实例,并且Service类所声明的Dependency这个时候就被注入到Worker,协同完成业务功能。Worker的生命周期在Service函数调用完毕就结束了,一个Service可以同时运行多个Workers,具体的Workers数目可自定义。 依赖提供者RpcProxy的生命周期和Service服务一样,而实际的get_dependency返回的注入对象的生命周期取决于其所注入的Worker实例。

ServiceRunner类

这个类用来封装ServiceContainer类,即功能是管理一系列ServiceContainer对象的启动停止。还记得吧,他的start函数里面有一行“SpawningProxy(self.containers).start()”代码,这行代码最后调用到了ServiceContainer的start函数. 允许用户同时提供多个服务。 调用方可以注册多个具有名称和的服务类 然后使用start方法为它们服务,使用stop和kill方法 去制止他们。等待方法将阻塞,直到所有服务都停止。

SpawningProxy类

这个类主要用来进行eventlet相关的调用,它先生产一个GreenPool,然后遍历所有的ServiceContainers对象,针对每个对象调用start函数,运行在一个green thread中。

里面多处使用spawn函数,表示待执行container超过线程池大小,新的任务会阻塞等待,可通过下述参数调整 max_workers:默认10,配置参数max_workers

AMQP

即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。Erlang中的实现有 RabbitMQ等。 我们需要明确的定义服务器的语义,因为所有服务器实现都应该保持这些语义的一致性,否则就无法进行互操作。 因此AMQP模型描述了一套模块化的组件以及这些组件之间进行连接的标准规则。

RabbitMQ

在服务器中,三个主要功能模块连接成一个处理链完成预期的功能:

“exchange”接收发布应用程序发送的消息,并根据一定的规则将这些消息路由到“消息队列”。
“message queue”存储消息,直到这些消息被消费者安全处理完为止。
“binding”定义了exchange和message queue之间的关联,提供路由规则。
使用这个模型我们可以很容易的模拟出存储转发队列和主题订阅这些典型的消息中间件概念。

nameko与amqp交互采用如下模式

Exchange(
        exchange_name, type='topic', durable=True, auto_delete=True,
        delivery_mode=PERSISTENT)
        

nameko与rabbitmq交互模式说明

1.采用topic的路由方式;
2.exchange默认为rpc-nameko;
3.mq的队列名称与服务名称关联,比如服务名为user_service,则请求队列的名称为rpc-user_service,响应队列名为rpc.reply-user_service-随机数;
4.每个消费队列的prefetch_count取自max_works,即与消费服务线程数一致
5.为保证消息可靠性,rabbitmq会进行持久化,同时也会损耗一定的性能,在高并发情况下CPU会消耗比较大

namko的基本操作

运行服务

$ nameko run <module> [:<ServiceClass> ]
比如
$ nameko run bayes.project.svc.user
或
$ nameko run bayes.project.svc.user:User

发现并运行服务类。这将在前台启动服务并运行它直到进程终止。 可以使用--config开关覆盖默认设置

$ nameko run --config ./foobar.yaml <module> [:<ServiceClass> ]

与正在运行的服务交互

$ nameko shell
n.rpc.target_service.target_method()

增加一个后门端口,本地可以使用命令行访问服务,不用nameko shell

nameko run --config config-test.yaml --backdoor-port 50000 server.testdpa
nameko backdoor 127.0.0.1:50000