openstack通用技术介绍

来源:互联网 发布:什么是数据新闻 编辑:程序博客网 时间:2024/05/01 22:26

1. 消息总线

Openstack遵循这样的设计原则:项目之间通过RESTful API进行通信;项目内部,不同的服务进程之间的通信,则必须通过消息总线。

1.1. AMQP(高级优先消息队列协议)


Openstack 组件内部的 RPC(Remote Producer Call)机制的实现是基于 AMQP(Advanced Message Queuing Protocol)作为通讯模型,从而满足组件内部的松耦合性。AMQP 是用于异步消息通讯的消息中间件协议,

Openstack目前已经支持了一些常见的消息总线

1)RabbitMQ
2)ZeroMQ
3)Qpid

RPC 远程过程调用

 通过远程过程调用,一个服务进程可以调用其他远程服务进程的方法,并且有两种调用方式

(1)cast 。远程方法会被异步调用

(2)call 。远程方法会被同步调用


AMQP 模型有四个重要的角色:

  • Exchange:根据 Routing key 转发消息到对应的 Message Queue 中
  • Routing key:用于 Exchange 判断哪些消息需要发送对应的 Message Queue
  • Publisher:消息发送者,将消息发送的 Exchange 并指明 Routing Key,以便 Message Queue 可以正确的收到消息
  • Consumer:消息接受者,从 Message Queue 获取消息

消息发布者 Publisher 将 Message 发送给 Exchange 并且说明 Routing Key。Exchange 负责根据 Message 的 Routing Key 进行路由,将 Message 正确地转发给相应的 Message Queue。监听在 Message Queue 上的 Consumer 将会从 Queue 中读取消息。

Routing Key 是 Exchange 转发信息的依据,因此每个消息都有一个 Routing Key 表明可以接受消息的目的地址,而每个 Message Queue 都可以通过将自己想要接收的 Routing Key 告诉 Exchange 进行 binding,这样 Exchange 就可以将消息正确地转发给相应的 Message Queue。

AMQP 消息模型:

AMQP 定义了三种类型的 Exchange,不同类型 Exchange 实现不同的 routing 算法:

  • Direct Exchange:Point-to-Point 消息模式,消息点对点的通信模式,Direct Exchange 根据 Routing Key 进行精确匹配,只有对应的 Message Queue 会接受到消息
  • Topic Exchange:Publish-Subscribe(Pub-sub)消息模式,Topic Exchange 根据 Routing Key 进行模式匹配,只要符合模式匹配的 Message Queue 都会收到消息
  • Fanout Exchange:广播消息模式,Fanout Exchange 将消息转发到所有绑定的 Message Queue

OpenStack 目前支持的基于 AMQP 模型的 RPC backend 有 RabbitMQ、QPid、ZeroMQ,对应的具体实现模块在 cinder 项目下 Openstack/common/RPC/目录下,impl_*.py 分别为对应的不同 backend 的实现。

接下来,我们看一个openstack中使用rpc的例子,例子是neutron中的代码,其他openstack项目nova cinder等也是用类似的流程

neutron代码:

   (1)neutron server初始化时会调用_setup_rpc和start_rpc_listeners初始化rpc相关资源

     代码路径neutron\plugins\ml2\plugin.py

    def _setup_rpc(self):    #创建一个rpc client,用于发送rpc消息,后面我会把AgentNotifierApi的代码附上        self.notifier = rpc.AgentNotifierApi(topics.AGENT)        self.agent_notifiers[const.AGENT_TYPE_DHCP] = (            dhcp_rpc_agent_api.DhcpAgentNotifyAPI()        )    def start_rpc_listeners(self):        self.endpoints = [rpc.RpcCallbacks(self.notifier, self.type_manager),                          securitygroups_rpc.SecurityGroupServerRpcCallback(),                          dvr_rpc.DVRServerRpcCallback(),                          dhcp_rpc.DhcpRpcCallback(),                          agents_db.AgentExtRpcCallback(),                          metadata_rpc.MetadataRpcCallback()]        self.topic = topics.PLUGIN        self.conn = n_rpc.create_connection(new=True)#创建rpc消费者        self.conn.create_consumer(self.topic, self.endpoints,                                  fanout=False)#开始监听消息        return self.conn.consume_in_threads()

(2)AgentNotifierApi类的实现:

代码路径neutron\plugins\ml2\rpc.py

当neutron server需要通知agent进行networkd_delete时就会调用network_delete函数,network_delete中使用rpc的异步消息通知agent

class AgentNotifierApi(dvr_rpc.DVRAgentRpcApiMixin,                       sg_rpc.SecurityGroupAgentRpcApiMixin,                       type_tunnel.TunnelAgentRpcApiMixin):    """Agent side of the openvswitch rpc API.    API version history:        1.0 - Initial version.        1.1 - Added get_active_networks_info, create_dhcp_port,              update_dhcp_port, and removed get_dhcp_port methods.    """    def __init__(self, topic):        self.topic = topic        self.topic_network_delete = topics.get_topic_name(topic,                                                          topics.NETWORK,                                                          topics.DELETE)        self.topic_port_update = topics.get_topic_name(topic,                                                       topics.PORT,                                                       topics.UPDATE)        target = messaging.Target(topic=topic, version='1.0')        self.client = n_rpc.get_client(target)    def network_delete(self, context, network_id):        cctxt = self.client.prepare(topic=self.topic_network_delete,                                    fanout=True)#发送异步消息       cctxt.cast(context, 'network_delete', network_id=network_id)    def port_update(self, context, port, network_type, segmentation_id,                    physical_network):        cctxt = self.client.prepare(topic=self.topic_port_update,                                    fanout=True)       cctxt.cast(context, 'port_update', port=port,                   network_type=network_type, segmentation_id=segmentation_id,                   physical_network=physical_network)


2. SQLAlchemy

SQLAlchemy是Python编程语言下的一款开源软件。提供了SQL工具包及对象关系映射(ORM)工具,使用MIT许可证发行。

SQLAlchemy“采用简单的Python语言,为高效和高性能的数据库访问设计,实现了完整的企业级持久模型”

SQLAlchemy主要分成两部分:

SQLAlchemy Core(SQLAlchemy核心):包含SQL语言表达式、数据引擎、连接池等

SQLAlchemy ORM(SQLAlchemy 对象关系映射器):提供数据映射模式(也即是把程序语言对象数据映射成数据库中的关系数据)


架构图:


3. RESTful API和WSGI

3.1.RESTful

RESTful是一种互联网软件架构。REST(Representational State Transfer,表述性状态转移)是一种软件架构风格。如果一个架构符合REST原则,就称它为RESTful架构。


要理解RESTful架构,最好的方法就是去理解Representational State Transfer这个词组到底是什么意思,它的每一个词代表了什么涵义。如果你把这个名称搞懂了,也就不难体会REST是一种什么样的设计。

3.1.1.资源(Resources

REST的名称"表述性状态转化"中,省略了主语。"表述性"其实指的是"资源"Resources)的"表述性"

所谓"资源",就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实在。你可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI。要获取这个资源,访问它的URI就可以,因此URI就成了每一个资源的地址或独一无二的识别符。

所谓"上网",就是与互联网上一系列的"资源"互动,调用它的URI

3.1.2.表述性(Representation

"资源"是一种信息实体,它可以有多种外在表现形式。我们把"资源"具体呈现出来的形式,叫做它的"表述性"Representation)。

比如,文本可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式;图片可以用JPG格式表现,也可以用PNG格式表现。

URI只代表资源的实体,不代表它的形式。严格地说,有些网址最后的".html"后缀名是不必要的,因为这个后缀名表示格式,属于"表现层"范 畴,而URI应该只代表"资源"的位置。它的具体表现形式,应该在HTTP请求的头信息中用AcceptContent-Type字段指定,这两个字段 才是对"表述性"的描述。

3.1.3.状态转化(State Transfer

访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,势必涉及到数据和状态的变化。

互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生"状态转化"State Transfer)。而这种转化是建立在表述性之上的,所以就是"表述性状态转化"

客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GETPOSTPUTDELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。

3.1.4.综述

综合上面的解释,我们总结一下什么是RESTful架构:

  (1)每一个URI代表一种资源;

  (2)客户端和服务器之间,传递这种资源的某种表现形式(表述性);

  (3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表述性状态转化"


4. Eventlet

eventlet是一个用来处理和网络相关的python库函数,而且可以通过协程来实现并发,在eventlet里,把“协程”叫做 greenthread(绿色线程)。

 

一个进程中,利用python库Eventlet可以产生出许多个协程,这些协程之间只有在调用到了某些特殊的Eventlet库函数的时候(比如sleep,I/O调用等)才会发生切换

 

    协程(coroutine)有下面几个特点。

    1.每个协程都有自己的私有stack及局部变量,同时又于其他协程共享全局变量;

    2.同一时间内只有一个协程在运行,故无须对某些共享变量加锁;

3.协程之间的执行顺序,完成由程序来控制;

 

协程的实现主要是在协程休息时把当前的寄存器保存起来,然后重新工作时再将其恢复。

一篇讲Eventlet的博客:

http://blog.csdn.net/gaoxingnengjisuan/article/details/12913275

5. OpenStack通用库Oslo

Oslo功能:独立出系统中可重用的基础功能

5.1.Cliff

可以用来帮助构建命令行程序

5.2.oslo.config

oslo.config库用于解析命令行和配置文件的配置选项

5.3.oslo.db

oslo.db是针对SQLAlchemy访问的抽象

5.4.oslo.i18n

oslo.i18n是对Python getext模块的封装,主要用于字符串的翻译和国际化。

5.5.oslo.messaging

oslo.messaging库为OpenStack各个项目使用RPC和时间通知提供了一套统一的接口。

5.6.stevedore

stevedore基于setuptools entry point(http://packages.python.org/distribute/pkg_resources.html#convenience-api),提供python应用程序管理插件的功能。

stevedore就是在Setuptools的entry points基础上,构造了一层抽象成,使开发者可以更容易地在运行时发现和载入插件

使用stevdore来帮助程序动态载入插件的过程:

(1)插件的实现

(2)插件的注册

(3)插件的载入

5.7.TaskFlow

通过TaskFlow库,可以更容易地控制任务(Task)的执行。

5.8.cookiecutter

5.9.oslo.policy

5.10.oslo.rootwrap

5.11.oslo.test



******************************************未完待续

1 0
原创粉丝点击