zoukankan      html  css  js  c++  java
  • OpenStack 通用技术有哪些

    来自: http://1.chaoxu.sinaapp.com/archives/3858

    OpenStack遵循这样的设计原则,“不要重复发明轮子”,即对已实现的功能,开发者直接拿来用即可。这一设计原则最终形成了一个由专门团队维护的Oslo——OpenStack公共库,实现硬件、操作系统和应用程序等的松耦合。

    一.消息总线(MQ)

    OpenStack的各项目之间通过REST ful API进行通信;项目内部、不同服务进程之间的通信,则必须要通过消息总线。软件从最初的面向过程、面向对象、再到面向服务,要求我们去考虑各个服务之间 如何传递消息,借鉴硬件总线的概念,引入了消息总线的模式,顾名思义,一些服务向总线发送消息,其他服务则从总线上获取消息。

    OpenStack对很多消息总线的开源实现提供了支持,比如RabbitMQ、Qpid等。基于这些消息总线类型,OpenStack oslo.messaging库实现了以下两种方式来完成项目内部各服务进程之间的通信。

    远程过程调用(RPC)

    通过远程过程调用,一个服务进程可以调用其他服务进程的方法,并且有两种调用方式,call和cast。通过call的方式调用,远程方法会被 同步执行,调用者会被阻塞直到结果返回。通过cast方式调用,远程方法会被异步执行,结果并不会立即返回,调用者也不会被阻塞,但是调用者需要利用其他 方式查询这次远程调用的结果。

    事件通知(Event Notification)

    某个服务进程可以把时间通知发送到消息总线上,该消息总线上所有对此类事件感兴趣的服务进程,都可以获得此事件通知并进行下一步的处理,处理的 结果并不会返回给事件发送者。这种通信方式,不但可以在同一个项目内部的各个服务进程之间发送通知,也可以实现跨项目之间的通知发送。 Ceilometer就通过这种方式大量获取其他OpenStack项目的事件通知,从而进行计量和监控。

    1.AMQP(高级消息队列协议)

    OpenStack支持的消息总线类型中,大部分都是基于AMQP的。AMQP是一个异步的应用层消息传递开放协议,主要包括了消息的导向、消 息交换、消息队列和路由。对于一个使用了AMQP的中间件服务而言,当不同的消息由生产者(Producer)发送到Server时,它会根据不同的条件 把消息传递给不同的消费者(Consumer)。如果消费者无法接收消息或者接收消息不够快时,它会把消息缓存在内存或者磁盘上。

    2.基于AMQP实现RPC

    3.OpenStack支持的常见消息总线类型

    1)RabbitMQ

    2)Qpid

    3)ZeroMQ

    二.SQLAlchemy和数据库(Shane)

    SQLAlchemy是Python语言下的一款开源软件,提供了SQL工具包以及对象关系映射器ORM,这样SQLAlchemy便能让Python开发人员简单灵活地运行SQL操作后台数据库。

    SQLAlchemy主要分成两部分,SQLAlchemy Core和SQLAlchemy ORM。前者主要包括SQL语言表达式、数据库引擎、连接池等,其目的是为了实现连接不同的后台数据库、提交查询和更新SQL请求去后台执行。 SQLAlchemy ORM提供数据映射模式,也就是把程序语言的对象数据映射成数据库中的关系数据,或者把关系数据映射成对象数据。

    需要注意的是,如果程序用了对象关系映射器,虽然好处极多,但程序性能会受到一定影响。因此,对象关系映射是一个可选的模块,而开发人员即便不用任何对象关系映射也能直接用SQLAlchemy操作数据。

    三.RESTful API和WSGI

    OpenStack项目都是通过RESTful API向外提供服务,这使得OpenStack的接口在性能、可扩展性、可移植性、易用性等方面做到了比较好的平衡。

    1.什么是REST ful API

    如果一个软件架构符合REST原则,我们就称它为RESTful架构。

    RESTful架构的一个核心概念是“资源”。从RESTful的角度看,网络中的任何东西都是资源。它可以是一段文本、一张图片、一首歌曲、一种服务等,每个资源都对应于一个特定的URL,并用它进行标示,访问这个URL就可以获得此资源。

    资源可以有多种具体的表现形式,也就是资源的“表述”(Represent),比如一张图片可以是JPEG格式也可以是PNG格式,URL代表的是资源实体,而不是表现形式。

    客户端和服务端之间的互动传递就是资源的表述。我们上网浏览网页,就是在调用资源的URL,获取它不同表现形式的过程,这种互动只能使用无状态 协议HTTP,也就是说,服务端必须保存所有的状态,客户端可以使用包括GET、POST、PUT和DELETE这些在内的基本操作,使服务端上的资源发 生“状态转移”,也就是所谓的“表述性状态转移”

    2.RESTful路由

    Openstack各个项目都提供了RESTful架构的API作为对外提供的接口,而RESTful架构的核心是资源和资源上的操作。也就是说,OpenStack定义了很多的资源,并实现了针对这些资源的各种操作函数。

    当OpenStack 的API服务进程接收到客户端的HTTP请求时,一个所谓的路由模块会将请求的URL转换成相应的资源,并路由到合适的操作函数上。OpenStack使用的路由模块是Routers。

    比如,当我们执行“neutron router-list”命令时,Neutron客户端(neutron_client)将这个命令转换成HTTP请求发送给Neutron的server服务进程,然后被路由到下面代码中的“index”操作。

    # neutron/api/v2/router.py
    43 class Index(wsgi.Application):
     44     def __init__(self, resources):
     45         self.resources = resources
     46 
     47     @webob.dec.wsgify(RequestClass=wsgi.Request)
     48     def __call__(self, req):
     49         metadata = {'application/xml': {'attributes': {
     50                     'resource': ['name', 'collection'],
     51                     'link': ['href', 'rel']}}}
     52 
     53         layout = []
     54         for name, collection in self.resources.iteritems():
     55             href = urlparse.urljoin(req.path_url, collection)
     56             resource = {'name': name,
     57                         'collection': collection,
     58                         'links': [{'rel': 'self',
     59                                    'href': href}]}

    3.什么是WSGI

    RESTful只是软件设计的风格而不是标准,Web服务中通常使用基于HTTP的符合RESTful风格的API。而WSGI(Web服务器网关接口)则是Python语言中所定义的Web服务器和Web应用程序之间的通用接口标准。

    WSGI是一个网关,作用是在协议之间进行转换。也就是说,WSGI是一座桥梁,桥梁的一端称为服务端或者网关端,另一端称为应用端或者框架 端。当处理一个WSGI请求时,服务端为应用端提供上下文信息和一个回调函数,应用端处理完请求之后,使用服务端提供的回调函数返回相对应的请求响应。

    作为一个桥梁,WSGI将Web组件分成了三类,Web服务器(WSGI Server)、Web中间件(WSGI Middleware)与Web应用程序(WSGI APPlication)。WSGI Server接收http请求,封装一系列的环境变量,调用注册的WSGI Application,最后将响应返回给客户端。

    WSGI Application是一个可被调用的Python对象,它接受两个参数,通常为environ和start_response。如下一个Neutron项目中关于Server的功能测试列子:

    # neutron/tests/functional/test_server.py
    177     def application(environ, start_response):
    178         """A primitive test application."""
    179 
    180         response_body = 'Response'
    181         status = '200 OK'
    182         response_headers = [('Content-Type', 'text/plain'),
    183                             ('Content-Length', str(len(response_body)))]
    184         start_response(status, response_headers)
    185         return [response_body]

    其中,参数environ指向一个Python字典,WSGI Application可以从environ字典中获取相对应的请求及其执行上下文的所有信息。而参数start_response指向一个回调函数,如 下所示一个Neutron项目中关于WSGI的单元测试列子:

    # vim neutron/tests/unit/test_wsgi.py
    161         def hello_world(env, start_response):
    162             if env['PATH_INFO'] != '/':
    163                 start_response('404 Not Found',
    164                                [('Content-Type', 'text/plain')])
    165                 return ['Not Found
    ']

    字符串“404 Not Found”用于表示请求响应的状态,“’Content-Type’, ‘text/plain’”是一个分别代表了header_name,header_value的元组列表。也就是HTTP响应中的http报头和内容。

    WSGI中间件同时实现了服务端和应用端的API,因此可以在两端之间起协调沟通作用,在服务端看来,中间件就是一个WSGI应用;在应用端看来,中间件则是一个WSGI服务器。

    WSGI中间件可以将客户端的HTTP请求,路由给不同的应用对象,然后将应用处理后的结果返回给客户端。自然,我们也可以将WSGI中间件理 解为服务端和应用端交互的一层包装,经过不同中间件的包装,便具有不同的功能,比如URL路由分发,再比如权限认证,这些不同中间件的组合便形成了 WSGI的框架,比如Paste。

    4.什么是Paste

    OpenStack使用Paste的Deploy组件来完成WSGI服务器和应用的构建,每个项目源码的etc目录下都有一个Paste配置文 件,比如Neutron中的/etc/neutron/api-paste.ini,部署时,这些配置文件会被复制到系统的/etc /Project_name目录下。Paste Deploy的工作便是基于这些配置文件。

    Paste配置文件分为多个Section,每个Section以type:name的格式命名。使用Paste Deploy的主要目的是从配置文件中生成一个WSGI Application,有了配置文件之后,只需要使用下面的调用方式。

    from paste.deploy import loadapp
    wsgi_app = loadapp(‘config:/path/to/config.ini’)

    5.什么是WebOb

    除了Routers与Paste Deploy外,OpenStack中另一个与WSGI密切相关的是Webob。Webob通过对WSGI的请求与响应进行封装,来简化WSGI应用的编写。

    6.什么是Eventlet

    Openstack中的绝大部分项目都采用了协程模型。在操作系统看来,一个Openstack服务只会运行在一个进程中,但在这个进程 中,OpenStack巧妙的地利用了Python的网络库Eventlet产生出许多个协程(绿色线程),这些协程之间只有在调用到了某些特殊的 Eventlet库函数的时候(比如睡眠sleep、I/O调用等)才会发生切换。

    与线程类似,协程也拥有自己独立的栈和局部变量,同时,又与其他协程共享全局变量。协程与线程的主要区别是,多个线程可以同时运行,而同一时间内只能有一个协程在运行,无须考虑很多锁的问题。

    使用线程时,线程的执行完全由操作系统控制,而使用协程时,协程的执行顺序、时间完全由程序自己决定,由于工作方式为主动模式,所以可以最大化 的利用CPU性能。协程的实现主要是在协程休息时把当前的寄存器保存起来,然后重新工作时再将其恢复过来,因此,协程可以理解为一个线程内的伪并发方式 (并发也就是指创建多个绿色线程)。

    7.什么是AsynclO

    目前,OpenStack社区正在考虑使用AsyncIO来代替Eventlet。AsyncIO可以看做是许多第三方Python库的超集,包括Twisted、Eventlet等。

    三.OpenStack通用库Oslo

    1.Cliff

    Cliff,是OpenStack中用来帮助构建命令行程序的通用库。主程序负责基本命令行参数的解析,然后调用各个子命令去执行不同的操作。

    2.oslo.config

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

    3.oslo.db

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

    4.oslo.i18n

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

    5.oslo.messaging

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

    为了支持不同的RPC后端实现,oslo.messaging对如下的对象进行了统一:

    Transport

    Transport传输层主要实现RPC底层的通信,比如Socket以及事件循环、多线程等其他功能。

    Target

    Target封装了指定某一个消息最终目的地的所有消息。

    Server

    一个RPC服务器可以暴漏多个endpoint,每个endpoint包含一组方法。

    RPC Client

    通过RPC Client可以远程调用RPC Server上的方法,有cast和call两种远程调用方式。

    Stevedore

    在Python代码运行时动态发现和载入所谓的插件“Plugin”,使得程序更容易的扩展,Python库Stevedore就是在 setuptools的entry points基础上,构造了一层抽象层。使用Stevedore实现程序动态载入插件的过程主要分为三个部分:插件的实现;插件的注册,以及插件的载入。

    Taskflow

    通过Taskflow通用库,可以更容易的控制任务(Task)的执行。Task、flow和engine是Taskflow中的几个基本概念。

    Task是Taskflow库中拥有执行(execute)和回滚(revert)功能的最小单位(实际最小单位是atom,其他所有类包括 task类都是Atom类的子类),然后新建一个线性流flow。而engine用来载入一个flow,然后驱动该flow中的task/flow运行。

    Cookiecutter

    开发人员,可以使用openstack的Cookiecutter通用库模板,新建一个符合惯例的openstack项目。

    Oslo.policy

    Policy用于控制用户的权限,能够执行什么样的操作,openstack的每个项目中都有一个/etc/project_name /policy.json文件,可以通过配置该文件来实现对用户的权限管理。将policy操作的公共部分提取出来,便形成了oslo.policy通用 库。

    Oslo.rootwrap

    Oslo.rootwrap可以让openstack服务以root身份去执行一些shell命令。一般来说openstack的服务都是以普 通用户的身份去运行的,但是当他们需要以root身份去执行一些shell命令时,便需要利用到oslo.rootwrap的功能。

    Oslo.test

    Oslo.test库是openstack中提供单元测试的基础框架或通用库。Oslo.test基于testtools库定义了oslotest.base.BaseTestCase类,可以作为其他openstack项目单元测试的基类。

    比如,在下面的neutron/tests/unit/api/v2/test_resource.py文件中:

    28 class RequestTestCase(base.BaseTestCase):
     29     def setUp(self):
     30         super(RequestTestCase, self).setUp()
     31         self.req = wsgi_resource.Request({'foo': 'bar'})
     32
     33     def test_content_type_missing(self):
     34         request = wsgi.Request.blank('/tests/123', method='POST')
     35         request.body = b"<body />"
     36         self.assertIsNone(request.get_content_type())
     37
     38     def test_content_type_with_charset(self):
     39         request = wsgi.Request.blank('/tests/123')
     40         request.headers["Content-Type"] = "application/json; charset=UTF-8"
     41         result = request.get_content_type()
     42         self.assertEqual(result, "application/json")

    使用BaseTestCase作为基类时,单元测试中创建的所有临时文件都会被存放在一个单独的目录中,此时系统环境变量HOME也会被设置成一个临时的目录。

    BaseTestCase类提供了方法create_tempest()来创建临时文件:

    Create_tempfiles(files, ext=’.conf’)
    参数:files(元组的列表),包含了类似(文件名、文件内容)的元组列表
          ext(字符串),新建的文件扩展名
    返回:所有新建的文件名列表

    oslo.test通用库除了提供上面的基类之外,还提供了两个通用的fixture,oslotest.mockpatch和 oslotest.moxstubout供其他Openstack项目开发单元测试用例。不过,一般建议使用oslotest.mockpatch。比 如:

    Oslotest通用库提供了一个debug脚本用来支持在测试中使用pdb。

    1)在代码中设置调试:

    import pdb; pdb.set_trace()

    2)在Openstack项目的tox.ini配置文件中加入如下行:

    [ testenv:debug]
    commands = oslo.debug_helper.sh {posargs}

    3)运行类似下面的命令来触发断点,进入Python debugger:

    # tox –e debug
    # tox –e debug 程序模块名.类名.方法名
  • 相关阅读:
    .Net 开源项目资源大全
    无法向会话状态服务器发出会话状态请求
    网站限制不能点击右键
    ashx页面中context.Session["xxx"]获取不到值的解决办法
    SQL Server 2008 错误 233 的解决办法
    Best MVC Practices 最佳的MVC实践
    char* 转换成 CString
    MFC圆角背景移动边角底色毛刺解决方案
    CString转换为const char*
    分享一份安卓开发包,集成开发环境
  • 原文地址:https://www.cnblogs.com/kevinX/p/5458315.html
Copyright © 2011-2022 走看看