关于
我的项目
相关阅读
热度排行
- [转] 宫崎骏用动漫教给我们的人生哲理,每一句都能说到心里! - (日期:[八月 24, 2013] 点击:[53,164])
- Google 网页爬虫报告无法连接站点解决办法 - (日期:[七月 20, 2014] 点击:[38,630])
- 架设Tiny Tiny RSS(TTRSS)阅读器,找回Google Reader! - (日期:[九月 27, 2013] 点击:[27,764])
- SkyDrive、DropBox和Google Drive三大公有云存储服务对比 - (日期:[六月 25, 2013] 点击:[25,564])
- 升级到至强E5440后,与i5 CPU笔记本性能对比 - (日期:[二月 18, 2014] 点击:[23,696])
- 公钥私钥加密解密数字证书数字签名详解 - (日期:[四月 19, 2014] 点击:[22,955])
- 本站建站技术合集 - (日期:[九月 20, 2013] 点击:[22,481])
- 使用OpenerDNS解决无法访问Google的问题 - (日期:[七月 5, 2014] 点击:[21,774])
- WordPress博客添加“返回顶部”按钮 - (日期:[七月 14, 2013] 点击:[21,189])
- Linux文件系统基础之inode和dentry - (日期:[三月 13, 2015] 点击:[20,161])
- 云存储中的HTTP鉴权算法分析 - (日期:[二月 7, 2014] 点击:[18,636])
- 存储基础知识之——磁盘阵列原理及操作实战 - (日期:[二月 9, 2014] 点击:[17,478])
- 精选37条强大的常用linux shell命令组合 - (日期:[九月 4, 2013] 点击:[17,425])
- DNS原理、架构和配置详解 - (日期:[九月 6, 2013] 点击:[16,797])
- Netty和Jetty的Java NIO 网络框架模型分析 - (日期:[七月 13, 2013] 点击:[16,329])
- CoreOS 初识之安装 - (日期:[十一月 16, 2014] 点击:[16,162])
- Windows与Linux文件系统互访的几种方法 - (日期:[八月 21, 2014] 点击:[15,725])
- Dijkstra算法求解最短路径分析 - (日期:[七月 12, 2014] 点击:[14,921])
- NAS解决方案实现多媒体文件共享播放 - (日期:[十二月 21, 2014] 点击:[13,899])
- 简介 - (日期:[九月 1, 2012] 点击:[13,747])
- 如何编程实现 2 + 2 = 5? - (日期:[六月 2, 2014] 点击:[13,266])
- 搭建了一个iNews程序 - (日期:[十月 15, 2013] 点击:[13,233])
- 2014年9月曝出的Bash ShellShock漏洞简析 - (日期:[九月 26, 2014] 点击:[13,134])
- 彻底解决WordPress博客垃圾评论的问题 - (日期:[八月 5, 2013] 点击:[13,080])
- 如何使用1M的内存排序100万个8位数 - (日期:[三月 27, 2014] 点击:[12,551])
- 全部日志列表 - (日期:[十一月 11, 2012] 点击:[12,317])
- 关于回调函数和this指针探讨 - (日期:[八月 24, 2014] 点击:[12,206])
- 给定一个long型常量,其值为x,给定long型变量a,要求a & x 的取值集合 - (日期:[九月 8, 2012] 点击:[11,695])
- WordPress建站必备实用插件 - (日期:[八月 7, 2014] 点击:[11,357])
- Amazon 云计算业务全面介绍 - (日期:[三月 9, 2014] 点击:[11,264])
分类目录
文章归档
- 2024年四月 (1)
- 2024年二月 (1)
- 2023年九月 (1)
- 2023年一月 (1)
- 2022年十月 (1)
- 2022年八月 (2)
- 2022年四月 (1)
- 2022年三月 (1)
- 2021年十二月 (2)
- 2021年十月 (2)
- 2021年九月 (1)
- 2021年八月 (1)
- 2021年五月 (1)
- 2021年三月 (2)
- 2021年一月 (2)
- 2020年十二月 (5)
- 2020年十一月 (2)
- 2020年十月 (2)
- 2020年九月 (1)
- 2020年八月 (5)
- 2020年七月 (2)
- 2019年九月 (1)
- 2018年八月 (1)
- 2018年七月 (1)
- 2018年六月 (1)
- 2018年五月 (1)
- 2018年三月 (1)
- 2018年二月 (1)
- 2018年一月 (2)
- 2017年十二月 (3)
- 2017年十月 (4)
- 2017年九月 (1)
- 2017年七月 (1)
- 2017年六月 (1)
- 2016年十二月 (1)
- 2016年十月 (1)
- 2016年九月 (1)
- 2016年七月 (2)
- 2016年六月 (1)
- 2016年二月 (3)
- 2015年十二月 (3)
- 2015年十一月 (2)
- 2015年十月 (1)
- 2015年八月 (2)
- 2015年七月 (4)
- 2015年六月 (1)
- 2015年三月 (2)
- 2015年二月 (1)
- 2015年一月 (4)
- 2014年十二月 (2)
- 2014年十一月 (2)
- 2014年十月 (5)
- 2014年九月 (8)
- 2014年八月 (11)
- 2014年七月 (17)
- 2014年六月 (7)
- 2014年五月 (15)
- 2014年四月 (16)
- 2014年三月 (14)
- 2014年二月 (5)
- 2013年十二月 (5)
- 2013年十一月 (3)
- 2013年十月 (13)
- 2013年九月 (13)
- 2013年八月 (13)
- 2013年七月 (9)
- 2013年六月 (8)
- 2013年五月 (1)
- 2013年三月 (3)
- 2013年一月 (1)
- 2012年十一月 (1)
- 2012年九月 (12)
- 2012年八月 (3)
- 2011年二月 (1)
- 2009年三月 (1)
- 2009年二月 (1)
- 2008年十一月 (1)
- 2008年六月 (1)
- 2008年四月 (1)
- 2008年三月 (1)
OpenStack Swift源码导读之——业务整体架构和Proxy进程
OpenStack的源码分析在网上已经非常多了,针对各个部分的解读亦是非常详尽。这里我根据自己的理解把之前读过的Swift源码的一些要点记录一下,希望给需要的同学能带来一些帮助。
一、Swift的整体框架图
如上图,Swift的源码目录结构。其中proxy是前端的业务接入进程。account、container和object目录分别是账户、容器和对象的业务处理逻辑进程。common目录是一些通用工具代码。common中比较重要的有:哈希环的处理逻辑。接下来会依次介绍各个进程的源码逻辑和一些关键点机制。
各个业务进程或模块之间的逻辑关系可以参考《Openstack Swift简介》文中的架构图。
二、Proxy进程的业务处理
首先需要掌握基于PasteDeploy的堆栈式WSGI架构。根据PasteDeploy定义的各个层,可以很快理清配置文件定义的代码流程,从middleware到server。找到最外层的middleware,即是业务的入口。对于proxy进程,可以简单给出业务时序图:
每一层的分工非常清晰,如在proxy进程默认配置文件中,最上层是做异常处理,所有的业务流程抛出的未处理的异常,在这里都将得到处理。
Proxy进程会分析请求的URI(account、container和object组成的资源路径)和请求方法(put、del等)来分析当前请求的资源的具体类型,然后分别找到控制该资源的controller,由controller来分发请求到具体的资源server。分发的原则是一致性哈希环。一致性哈希环在系统初始化时由工具生成,在《Swift 和 Keystone单机安装总结》一文中有具体的操作步骤。
在《Openstack Swift简介》从理论上面介绍了具体的节点寻找过程。采用md5值加移位的方式来确定part,然后找到所有的虚拟节点。具体的代码为:
container_partition, containers = self.app.container_ring.get_nodes(
self.account_name, self.container_name)
def get_nodes(self, account, container=None, obj=None):
"""
Get the partition and nodes
for an account/container/object.
If a node is responsible
for more than one replica, it will
only appear in the
output once.
:param account: account name
:param
container: container name
:param obj: object name
:returns: a tuple of (partition, list of node dicts)
Each node dict will have at least the following keys:
======
===============================================================
id unique integer
identifier amongst devices
weight a float of the
relative weight of this device as compared to
others;
this indicates how many partitions the builder will try
to assign
to this device
zone integer indicating
which zone the device is in; a given
partition
will not be assigned to multiple devices within the
same zone
ip the ip address of the
device
port the tcp port of the device
device the device's name on disk (sdb1, for
example)
meta general use 'extra'
field; for example: the online date, the
hardware
description
======
===============================================================
"""
part = self.get_part(account,
container, obj)
return part,
self._get_part_nodes(part)
def get_part(self, account, container=None, obj=None):
"""
Get the partition for an
account/container/object.
:param account: account name
:param
container: container name
:param obj: object name
:returns: the partition number
"""
key = hash_path(account, container, obj, raw_digest=True)
if time() >; self._rtime:
self._reload()
part = struct.unpack_from('>;I', key)[0] >>
self._part_shift
return part
def _get_part_nodes(self, part):
part_nodes = []
seen_ids = set()
for r2p2d in
self._replica2part2dev_id:
if
part <; len(r2p2d):
dev_id =
r2p2d[part]
if dev_id
not in seen_ids:
part_nodes.append(self.devs[dev_id])
seen_ids.add(dev_id)
return part_nodes
然后根据quorum原则来决定当前请求至少需要几个节点成功即可返回。如NWR分别为322,则至少需要2个节点写成功,才能确保此次写成功。体现在公用的make_request方法中:
def make_requests(self, req, ring, part, method, path, headers,
query_string=''):
"""
Sends an
HTTP request to multiple nodes and aggregates the results.
It attempts the primary nodes concurrently, then iterates
over the
handoff nodes as needed.
:param req: a request sent by the client
:param ring: the ring used for finding backend servers
:param part: the partition number
:param method: the method to send to the backend
:param
path: the path to send to the backend
(full path ends up being /<$device>/<$part>/<$path>)
:param headers: a list of dicts, where each dict
represents one
backend request that should be made.
:param query_string:
optional query string to send to the backend
:returns: a
swob.Response object
"""
start_nodes = ring.get_part_nodes(part)
nodes =
GreenthreadSafeIterator(self.app.iter_nodes(ring, part))
pile = GreenAsyncPile(len(start_nodes))
for head in
headers:
pile.spawn(self._make_request, nodes, part, method, path,
head, query_string, self.app.logger.thread_locals)
response = []
statuses = []
for
resp in pile:
if not resp:
continue
response.append(resp)
statuses.append(resp[0])
if self.have_quorum(statuses,
len(start_nodes)):
break
# give any pending requests *some* chance to finish
pile.waitall(self.app.post_quorum_timeout)
while len(response) <; len(start_nodes):
response.append((HTTP_SERVICE_UNAVAILABLE, '', '', ''))
statuses, reasons, resp_headers, bodies = zip(*response)
return self.best_response(req, statuses, reasons, bodies,
'%s %s' % (self.server_type, req.method),
headers=resp_headers)