Category Archives: 学习

关于读书,关于学习。

Neutron 的软件架构

综述

OpenStack 是目前开源界第二大的项目,参与的厂商之多可谓少见,同时作为目前最大的以 Python 作为主要语言的项目,可以说这个项目是经过重重困难发展起来的,算是目前在发展的分布式系统软件大作了,面对这么一个项目,我想我们有很多值得学习和借鉴的地方,因为时间和个人经验的缘故,我在这里主要与大家分享以 Neutron 为例的 OpenStack 软件设计。

Why Python

设计一个分布式系统可以说会面对诸多挑战,这不只是 Python 会遇到的,使用别的语言也会碰到,但是呢,Python 作为一个与 Java 等语言相比不够成熟的语言可能会面临一些其他可能已经在一些语言下解决了的问题,在 OpenStack 社区里就有人提过多次这个问题,为什么我们选择 Python,而非别的语言。

在我看来,一个大型软件的选型是一个复杂的事情,对于 OpenStack,可能第一是因为历史原因。因为我们知道 OpenStack 最早的源代码是 Rackspace 和 NASA 一起贡献的,他们当初内部的选择为我们建立了一个基调,如果再用其他语言重写的话,可能在当时是一个不合实际的考虑;再有,OpenStack 与其说是一个大型软件,倒不如说是一个框架,它的虚拟化来自于 KVM、Qemu 等的支持,它的网络来自于 Open vSwitch、iptables 等的支持,至于存储,也需要 lvm、Ceph 作为底层。那么 OpenStack 是干嘛的呢,它是一个总的调度器,集成这一切功能,完成一个真正的自由云计算软件。做运维的同学一般比较熟的语言都是 Shell、Python,老一点的可能熟悉 Perl,为什么?因为这些脚本语言,很适合做这种调度的工作,或者说它很适合做粘合剂,正如一些人称 Python 为“胶水语言‘一样,它能够方便的粘合各个组件,而且代码量相对少,可以让人专注于高层的事情,而不是为了底层费脑筋;再有,作为一个高级语言,Python 有着一些相对完美的特性,比如社区的有过提交的开发者有数千,活跃的开发者也有几百,为什么 OpenStack 能快速吸引这么多开发者,所有人都是之前就接触过 Python 么?不是的,很多人都是现学的,因为 Python 的基本语法真的很简单,只需要看一个晚上第二天就能阅读 OpenStack 基本的代码了,这对吸引开发者来说很有好处,就像为什么有些公司做项目首先考虑 Java,因为好招人啊!Python 作为一个学习曲线平滑的语言,可以说为吸引开发者带来很多方便。再有,反射、自省这些高级特性也不缺,这位开发带来了方便,丰富的库,比如Paste、Routes、requests、WebOb、alembic、Jinja2 等,更是提升前期效率的利器。

分布式系统中面临的问题

连接建立与服务初始化
事件分离与事件处理程序分派
IPC 与网络协议处理
静态和动态组件
并发与同步

Neutron 简介

因为很多人对 OpenStack 不那么熟,我就先简单介绍下 Neutron 是什么。Neutron 是 OpenStack 的虚拟网络组件,用洋气点的话说,就是一个 SDN 控制器。为什么我们需要虚拟网络?过去我们只给客户提供虚拟机,你花钱,我租你一台,想连接上就再买个公网 IP,就像很多人在 DigitalOcean 做得一样(当然 DigitalOcean 现在也有虚拟网络)。那有了虚拟网络可以干什么呢?我们来看一下 UStack 控制面板里的一张图:
Read More →

之前一直没有好好看过 Neutron API 服务的实现,这几天好好看了一下,对 WSGI、paste.deploy、Webob、routes 熟悉的人估计很快就能看完,可惜我对上面的概念/库没有个熟悉的,所以看了好久才看明白…… 下面是记录,这一部分主要是从 main 开始逐句分析 server 启动的大概过程,主要针对 API,对 RPC 的介绍等下次在看。

安装 Neutron-server 后,其将作为一个服务,启动,和别的服务一样,启动文件在 /etc/init.d,这里挑选部分:

. /etc/rc.d/init.d/functions  
# 执行 /etc/rc.d/init.d/functions,主要是引用里面的函数

prog=neutron
exec="/usr/bin/$prog-server"  # 目标执行文件是/usr/bin/neutron-server
configs=(
   "/usr/share/$prog/$prog-dist.conf" \
   "/etc/$prog/$prog.conf" \
   "/etc/$prog/plugin.ini" \
)  # 配置文件位置
pidfile="/var/run/$prog/$prog.pid"
logfile="/var/log/$prog/server.log"

[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog
#如果存在 /etc/sysconfig/neutron 则执行

lockfile=/var/lock/subsys/$prog-server

start() {
   [ -x $exec ] || exit 5  # 若 /usr/bin/neutron-server 存在且可执行则运行
   for config in ${configs[@]}; do
       [ -f $config ] || exit 6  # 检验文件是否存在且为普通文件
   done
   echo -n $"Starting $prog: "
   daemon --user neutron --pidfile $pidfile "$exec ${configs[@]/#/--config-file } --log-file $logfile &>/dev/null & echo \$! > $pidfile"
   # 引号部分比较复杂,其实是执行这么一句话:
   # "/usr/bin/neutron-server --config-file /usr/share/neutron/neutron-dist.conf
   # --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugin.ini --log-file
   # /var/log/neutron/server.log",并丢弃其输出,然后获得其 pid,把 pid 输出到
   # /var/run/neutron/neutron.pid,去掉执行 /usr/bin/neutron-server 时加的乱七八糟一大堆参数
   # 其实简化相当与这样:
   # daemon --user neutron --pidfile /var/run/neutron/neutron.pid /usr/bin/neutron-server
   # damon 是来自 /etc/rc.d/init.d/functions 用于产生 service 的函数
   retval=$? # 获取 damon 执行后的状态值
   echo
   [ $retval -eq 0 ] && touch $lockfile
   # 执行成功(状态值为0)则更新 /var/lock/subsys/neutron-server 的使用/更新时间为当前
   return $retval
}

ok,这个启动脚本主要还是执行 /usr/bin/neutron-server,我们看下这个脚本的内容:

#!/usr/bin/python
# PBR Generated from 'console_scripts'

import sys

from neutron.server import main

if __name__ == "__main__":
   sys.exit(main())

就是执行了一下 neutron.server.main(),下面我们来看下这个函数(server/__init__.py文件): Read More →

下面是部分源自我实习期间的调研报告,本作品采用知识共享Attribution-NonCommercial-NoDerivatives 4.0 国际许可协议进行许可,转载前请先联系作者(MatheMatrix)。

下面我们以这样一个场景来解释Open vSwitch如何在Neutron(OpenStack发挥作用),假定读者实践过前文第二章“Neutron与其他OpenStack模块安装 ”(暂未公开~不过基本类似于前边的OpenStack 安装脚本与常见问题),或对OpenStack有一定认识,最好实践过官方OpenStack安装手册的内容。

场景(一个租户,两个网络,一个路由,内部网络使用GRE,Libvirt VIF Driver使用LibvirtHybridOVSBridgeDriver):

场景一虚拟网络拓扑 场景一虚拟网络拓扑

Figure 11 场景一虚拟网络拓扑

如图我们有一个外网(External Network),IP段为172.16.0.0/16,两个内网,分别是Internal:10.18.0.0/24,和Internal2:10.22.22.0/24,值得注意的是这是两个网络(network),而不是子网(subnet)。

在这个场景下,计算节点的内部应当是这样的:

 

计算节点网络连接原理 计算节点网络连接原理

下面我将解释如何得到这幅图。 Read More →

虽然这个 OpenStack “自动”安装脚本已经写了有一段时间了,但一直也只是躺在 Github 上,没放出来,这几天总结下自己的客座生活,顺便把这个脚本拿出来吧 :-)

先说说这个简陋地轮子的用处:由于经常要测试,不时要往一些新机器装 OpenStack 或者将一些机器重装,我们既不想用 Devstack 装 Git 上的最新版,也不想用 PackStack 安装——感觉不能完全 controll :-)。因为之前跟着官方的文档(真心很长)装,感觉大部分过程都知道,所以就 follow 官方的安装文档写了下面的安装脚本,很简陋,只是用来避免照官方文档手打之苦:-) 。

需要说明的是,这个安装脚本补了一些我们按官方过程走时踩的坑,还做了一些假设,跑脚本前最后先看下,比如我们默认使用 GRE 配置网络,还默认了 mysql 的安装密码,还要求用户配好 hosts。当然可以自己改。

最出坑的地方当然是网络,首先 OpenStack 是可以安装在从只有一个网卡的一台虚拟机上到上千台机器的集群的,脚本默认网络节点有两个网卡,你也可以只用一个,但是 OVS 的网桥可千万不能省:-) 首先,请保证需要开得端口都开着,比如 MySQL 的
3306,HTTP 的80,NTP 的123(如果你像我只前一样在局域网自己搭建 NTP)等等。然后,Neutron 官方文档在 sudo 上有 bug,虽然我提交过了,但是貌似老版的文档并没有更新,就是这句:openstack-config --set /etc/neutron/neutron.conf agent \
root_helper sudo "neutron-rootwrap /etc/neutron/rootwrap.conf"
,一定要加引号,不然 neutron server 启不起来的,还有 neutron 的 sudo 工作也常会出些问题,需要我们干预下,在 sudoer 文件里加一行“neutron ALL=(ALL) NOPASSWD: ALL”,还有默认的“Defaults !visiblepw”也需要改成“Defaults visiblepw”。此外,建立 GRE 通道千万不要在 local ip 上用别名,必须用真实的 ip,不然也不会工作的。再就是 Horizon,为了能用多种域名/IP访问 Horizon,需要设置好 ALLOW-HOSTS,还有为了让 admin 正确登录,需要设置 OPENSTACK_KEYSTONE_DEFAULT_ROLE。最后,SELinux 经常阻止我们正常登录,不想调试像快速解决可以直接关掉它。

还有个深坑啊,就是官方文档居然没有说明我们在用 OVS 改了网后需要设置 network-scripts!怎么设置可以参考我的脚本。然后网络最好开开 namespace,方便些。还有,要用 OVSHybridIptablesFirewallDriver 来实现安全组的话,一定要在 nova 设置写好“libvirt_vif_driver=nova.virt.libvirt.vif.LibvirtHybridOVSBridgeDriver”,这点官方文档也没有说!

最后,安装基于 OpenStack Havana (2013.2.2),代码由 Redhat 打包,祝大家安装时能少遇坑,早享受! Read More →

最近在测试自己写的 OpenStack 安装脚本,之前都把控制节点和网络节点合在一起,这次为了把脚本分开,遇到了不少之前没有的问题,好在大部分都通过 Google + Docs 解决了,但是最近发现网络节点的 l3-agent 时常产生与消息服务器(控制节点)断开连接的问题:

2014-02-24 16:53:01.778 2378 ERROR neutron.openstack.common.rpc.impl_qpid [-] Failed to consume message from queue: heartbeat timeout

2014-02-24 16:53:01.784 2378 INFO neutron.openstack.common.rpc.impl_qpid [-] Connected to AMQP server on controller:5672

2014-02-24 18:31:00.829 2377 ERROR neutron.openstack.common.rpc.impl_qpid [-] Failed to consume message from queue: connection aborted

2014-02-24 18:31:00.836 2377 INFO neutron.openstack.common.rpc.impl_qpid [-] Connected to AMQP server on controller:5672

就像上面的日志显示那样,常常忽然连不上,然后再隔零点几秒又显示连接成功,让人看着非常不爽。前几天恰好看到了淘测试的一篇日志 GBA历代得主 ,里面提到淘宝的集群曾遇到过每个服务器都开了 NTP 同步时间,估计是连外网的 NTP 服务器对时把,造成了时间存在微小差异,导致心跳超时,我就心想我们的网络节点需要连 Qpid 服务器(控制节点),总是差那么零点几秒就会重连成功,而且我们的机器也都是开着 NTP 对时,是不是一个问题呢?

于是我就是试着用控制节点作为我们内网的授时服务器,整个内网都与整个授时服务器同步时间,这样用局域网速度应该会快很多,鸟哥的书固然好,但好像还是有些问题,我的配置过程如下:

一、修改控制节点的 /etc/ntpd.conf 文件,开放内网的访问(查询):

restrict 192.168.1.0 mask 255.255.255.0 nomodify notrap

至于连接哪个 NTP 服务器看喜好了,我一般使用的是 cn.pool.ntp.org。

二、开放防火墙123端口,设置完规则不要忘了保存:

iptables -A INPUT -p udp dport 123 sport 123 -j ACCEPT
iptables -A OUTPUT -p udp sport 123 dport 123 -j ACCEPT

三、重启ntp服务,用 ntpstat 和 ntpq -p 查看下我们的授时服务器与上层连接的状态,我这里 delay 一般在20~50左右(单位为毫秒),由于与 sysnet.edu.cn (屏幕没有显示全)延时最小,所以使用的是这个(在屏幕上用*注明):

> ntpstat:
synchronised to NTP server (202.112.31.197) at stratum 3
time correct to within 96 ms
polling server every 1024s> ntpq -p
remote refid st t when poll reach delay offset jitter
==============================================================================
*dns2.synet.edu. 202.118.1.46 2 u 420 1024 377 21.951 0.367 13.759
+dns.sjtu.edu.cn 202.112.29.82 3 u 567 1024 377 49.529 11.216 14.545
+Hshh.org 127.67.113.92 2 u 661 1024 377 48.000 -26.821 9.765

ntpq 的返回结果比较复杂,这里顺便解释下,refid 表示这个授时服务连接上一层授时服务器,在服务器名前加 * 表示是当前使用的服务器,st 指得是 stratum,里面的数字表示这个授时服务器的等级,详见鸟哥的介绍。t 这一列里边的 u 表示是 unicast 单播,在 NTP 服务中是最常见的方法,when 表示从上次连接已经过去了多久,单位是秒,poll 表示连接间隔,reach 表示是否成功,正常的话这里应该是377,delay 表示延时(应该是估计的吧)单位是毫秒,offset 表示本地与服务器的时间差,同样是毫秒,jitter 表示在反复获取时间时,获得的时间的差异,这个差异可能比较随机,详见 NTP 官网的 FAQ。 Read More →