Category Archives: 学习

关于读书,关于学习。

前言

说实话相比 OpenStack 往往流水式的代码且网络上分析和研究的文章比较多,ZStack 全异步、追求高稳定性和安全的代码是相对难读的,所以本文希望能通过一些简单的例子和与 OpenStack 的一些对比,将 ZStack 的特点、代码的原理尽量描述出来,降低 ZStack 的入门门槛。

第一步 前端

打开 Mevoco/ZStack 的界面,可以发现基本设计思路与其他 IaaS 或 OpenStack 是基本类似的,然而打开开发者面板就会发现大有不同。

OpenStack 的面板一般通过 HTTP 到 Web 后端,可能是一个像 Horizon 的中间件,也可能是直接把请求发到后面的具体服务的 API 服务,例如 nova-api 或 neutron-server。当然中间可能还会有负载均衡器或高可用之类的设施。

image_1b6dgt82i1rl0md5j8t8va1v4m9.png-305.3kB 图1 在OpenStack的Horizon面板上创建虚拟机出发的Post请求

而在 ZStack 的面板中开发者面板是很干净的,打开之后无论什么操作是不会触发 HTTP 请求的,数据和请求都在 WebSocket 传递,比如我们在面板上创建一个虚拟机,可以看到通过 WebSocket 发送一个 frame,发了一个 org.zstack.header.vm.APICreateVmInstanceMsg 的消息,后面跟着的是创建的参数。

image_1b6dhje891gd7rj61e551r9hv3vt.png-209.3kB 图2 ZStack面板上创建虚拟机发出的WebSocket帧

第二步 Web 后端

请求送到送到后端就需要我们登录到这个服务器上看了,我的实验环境是一个 All in One 的环境,登陆到服务器查询 5000 端口的监听情况,可以看到是一个 Python 程序在监听这个端口。

image_1b6dja8kukgq66ph0fs8m14hl1n.png-56.9kB

那么问题是这个程序怎么找到呢,现在我们不想去查部署程序是怎么部署的,然而直接在自己的 python 里直接 import 却报错提示没有这个库。

由于 Python 程序往往有比较重的依赖,因此 Python 部署是个运维中老生常谈的问题,想必这里是用了类似虚拟环境(virtualenv)之类的技术,那么问题就是那个虚拟环境在哪里。

我们知道 zstack 还有一个程序叫 zstack-cli,是 ZStack 的命令行程序,不妨查一下这个。可以看到这里定义了一个目录,到上面果然有几个目录,推测分别是 5 个 zstack 组件所使用的虚拟环境。

image_1b6djocjqbm218po1lob3c38mo2h.png-63.5kB

顺利找到 zstack-dashboard 目录后可以发现里边实际上没有多少 Python 代码,先打开 web.py,发现里边是一个小 Flask SocketIO App。

Flask SocketIO 用于实现 Web Socket 服务端,用 @socketio.on() 表示路由,参考图1,使用的是call,所以可以直接看处理call的 handle_call,跳转到server.api_call,将消息有 json 格式转换出来,然后连带一个用来发送回复的函数一起发给由CloudBus类所生成对象的send方法。

进入 CloudBus.send,通过一些检查和填充之后,设置回复的队列为zstack.ui.message.$uuid(这个 UUID 以及队列都是服务初始化时产生的)等等送给 Connection.send通过 kombu 对 P2P Exchange 以 zstack.message.api.portal 为 routing key(这里被封装为 Service ID)将消息发了出去。

Read More →

最近就这个问题调查了蛮久,其实原因比较显然,在看到 strace 的结果就已经明白了大半,但是本着求(xia)知(zhe)探(teng)索的想法,仔细验证了代码逻辑和时间(新技能 get!给 C++、Perl 混合代码调试性能),攒出了这篇文章。

ZStack 是一个开源的 IaaS 软件,架构和性能都很优秀,可以在 103 秒内并发创建 1000 台虚拟机,可惜这个数据是在扁平网络下测试得到的,一旦用上云路由网络,单个虚拟机的启动时间会延长到七秒左右。

我们现看下看下实际的占用时间,我在 vyatta 的代码里添加了日志(Repo 是 https://github.com/vyos/vyatta-cfg),综合 zstack、zstack-vyos、vyos 的日志可以看到大概是这样的(注意 zstack 的日志时间精度只提供到秒,没有毫秒):

2017-02-13 13:22:08 start executing flow[NetworkServiceManagerImpl.java:apply-network-service-DHCP]

2017-02-13 13:22:08 DEBUG [RECV] /setsnat
2017-02-13 13:22:09 DEBUG [HTTP POST][ASYNC REPLY TO /setsnat]

2017-02-13 13:22:09 DEBUG [RECV] /adddhcp

# 以下为 vyos 日志
2017-02-13 13:22:09:458 Entered cli_bin::doCommit
2017-02-13 13:22:10:216 Entered commit::doCommit
2017-02-13 13:22:10:901 notify other users in config mode
2017-02-13 13:22:12:260 cs.commitConfig complete
2017-02-13 13:22:12:557 Exit commit::doCommit
2017-02-13 13:22:12:557 Normal exit cli_bin::doCommit
# 退出 vyos 日志

2017-02-13 13:22:12 DEBUG [HTTP POST][ASYNC REPLY TO /adddhcp]

2017-02-13 13:22:12 DEBUG [RESPONSE] to /setdns
2017-02-13 13:22:12 DEBUG [HTTP POST][ASYNC REPLY TO /setdns]

2017-02-13 13:22:12 DEBUG [SimpleFlowChain] (zs-thread-81) [FlowChain: apply-network-service-to-vm-13d1359b8bd34a05a91f61dedb112e96] successfully executed flow[NetworkServiceManagerImpl.java:apply-network-service-DHCP]

可以把时间与调用关系结合起来做成一张图:

VyOS_Commit
Read More →

好久发博客了,透个气,其实在公司博客写了不少,但短篇为主,今天写了一篇长篇,发出来。

对于 OpenStack 原生的 Neutron 网络,往往诟病良多,核心问题就在性能无法满足生产环境的要求。一般来说,实验室数据往往需要是需求数据的几倍才能平稳、无明显延时的应对用户在真实生产环节下的复杂网络流量。

Neutron 的网络构成非常复杂,以一个典型的 OpenStack 网络节点为例,所使用的核心组件包括但不限于下面的模块/软件:

  • Linux Kernel 协议栈,包括系统软中断到完整的 TCP/IP 协议栈,用以收发报文、路由和策略路由等;
  • iptables,作为内核模块,与 conntrack 共同完成带状态的 DNAT 与 SNAT,如果有安全策略,例如 FWaaS 或者 LBaaS 的安全组,则也需要 iptables 过滤报文;
  • tc,用于收发报文的限速,例如浮动 IP 的限速,社区版代码并没有这部分,但如果厂商需要实现浮动 IP 限速,比较常见的方法是在这里做,此外如果有厂商希望提高 1:1 NAT 的性能,也可以通过 tc 实现,但比较少见;
  • Openswan、strongSwan、Libreswan,一般厂商会从中选取认为稳定、可靠的 Driver 提供简单的 IPSec VPN 功能;
  • Open vSwitch,作为虚拟交换机,要实现基本的二层交换功能,同时提供诸如流表、ARP 代答、二层标签替换等功能,如果想实现相对简单的流控功能,也可以通过 Open vSwitch,但目前应用厂商也较少;
  • VXLAN 模块,如果使用 VXLAN 网络,搭配内核 Datapath 的 Open vSwitch,则需要内核的 VXLAN 模块解析和封装外边的 VXLAN 报文;
  • HAProxy,作为 OpenStack 默认的 LBaaS Plugin(假定用户没有使用 Octavia,毕竟还比较新),为用户提供负载均衡功能;
  • Dnsmasq,作为 OpenStack 默认的 DHCP 的 Driver,为用户提供 DHCP Server 功能,还可以提供 DNS 查询;
  • 网卡驱动,包括物理网卡驱动例如 ixgbe,也包括虚拟网卡驱动例如 vport-internal,当然 internal 接口实际上是 Open vSwitch 代码的一部分。

(没有时间画一个很完整的图,这个图大概表现了内核网络的大概过程,可以参考下)

这么多组件、模块,集合在一台服务器上,调优的难度相当大。我们如果仔细考察整个过程对计算资源的使用(内存资源在 x86 中往往比较宽裕),其中协议栈部分和协议栈相关软件依赖 Namespace 隔离(然而,内核里的很多计算资源使用是无法隔离的),网卡的 Soft IRQ 其实是共用资源,只能通过哈希尽量分散对 CPU 资源的使用,Open vSwitch 的 Datapath 和 vswitchd 也很难说对用户做完整的资源隔离,因此总体来看,网络节点通过大量手段完成了网络通信的隔离(二层通信依赖 VLAN/VXLAN,三层以上依赖 Namespace),但是 IO 对计算资源的使用依然是一个很难解决的待处理难题。

一种思路是通过对网络通信的限制完成隔离,例如限制网络带宽和 PPS,其中限制带宽是一种比较不太有效的方法,例如我们允许虚拟机对外访问使用 1Gbps 带宽,相当于虚拟的一个千兆网卡,此时虚拟机小包线速可以发到 1.4Mpps,依然是一个很高的数字。在例如从外边收到攻击或者收到海量的报文,如果到 namespace 下的 tc 才做 QoS,很有可能 Open vSwitch 和网卡 softirq 都会瞬间跑满,以至一个用户影响所有用户。此时如果通过 Open vSwitch 控制带宽,效果会比 tc 好一些,如果使用 Flow director,效果可能会更好。

另一种思路是通过强隔离的手段分离用户对资源的使用,例如 NFV 思路,将网络功能封装在虚拟机里,这样资源隔离完全通过 Hypervisor 实现,设置 Flavor 和隔离资源都可以达到很好的效果,但目前 Neutron 社区的进展并不很突出。

无论哪种思路,大多都离不开 Open vSwitch,如何很好的评估 Open vSwitch 的性能、评估整个 Neutron 网络的性能因此成为一个对厂商比较困扰的问题。

简单来讲,评估测试的手段有以下这些(分类不完全科学,以尽量表现特点为主):

  1. 依赖内核协议栈的打流工具,如 iPerf、netperf 等;
  2. 依赖内核的打包工具,如 pktgen、hping、nping 等;
  3. 专业的测试仪表,例如思博伦、IXIA 等;
  4. 基于 dpdk 的打包工具如 dpdk-pktgen、moongen、trex 等。

其中:

1 的性能较弱,定制流的能力较差,难以反映准确结果;

2 的灵活性比较一般,难以超出其本身 scpoe 灵活打流,统计功能一般,性能也无法达到专业需求;

3 在各方面都是最佳之选,无奈价格昂贵,一般厂商难以承担,而且测试仪使用繁琐,效率不高;

4 我们测试过 moongen 和 trex,moongen 在测试过程中经常出现流打不稳的问题,而且统计功能一般,最终我们选择了 trex,并已经投入生产研发。

trex 的安装、编译非常简单,文档也比较全面,这里直接介绍两个简单的 use case:

  • 通过 trex 测试 Open vSwitch 的 VXLAN 二层性能;
  • 通过 trex 测试 VXLAN 拓扑下内核路由性能。

其中第一个我们可以这样测试:

其中呢,我们在 Trex 绑定两块网卡,Trex 所在服务器(TG)通过交换机连接到待测服务器(DUT),在 DUT 上配置 IP 地址 10.0.109.171/24,并在 Open vSwitch 上建立两条到 TG 的 VXLAN 隧道,Switch 上和 DUT 上配置 10.0.109.67 和 10.0.109.68 的静态 ARP(交换机上添加 CAM 即可),以避免内核协议栈发送 ARP 请求和交换机泛洪。图中实线表示实际物理连线,虚线表示隧道,虚线平行四边线表示这个 IP 通过静态 ARP 配置,并不是真实配置的 IP 地址,实线平行四边形表示配置在网口上的 IP 地址。

然后在 Open vSwitch 上添加流表,将 vxlan-port-1 口的流量直接转发给 vxlan-port-2,DUT 配置为 Intel(R) Xeon(R) CPU E5-2630 v3 @ 2.40GHz,Intel 82599ES,调整 pstate 为性能,开启超线程,将网卡 IRQ 绑定在本地 Node 上,开启 UDP RSS 的四元组哈希。

Trex 支持 Stateful 发包和 Stateless 发包,在这里我们使用后者。其内置 Scapy 版本为 2.3.1,这个版本没有直接支持 VXLAN,有两种处理方法,一是自己在发包脚本中修改,类似官方的实例:stl/udp_1pkt_vxlan.py,另一种方法是直接修改 scapy 的代码,为了方便起见,我们采用了后者:

创建一个文件:external_libs/scapy-2.3.1/python2/scapy/contrib/vxlan.py,内容如下: Read More →

五一期间写的,供大家观影 Austin 用

  • 前言
  • 架构
    • Practical OVN Architecture, Deployment, and Scale of OpenStack
    • OpenStack and Opendaylight The Current Status and Future Direction
    • OpenDay Light – Collaborating with OpenDaylight for a Network-Enabled Cloud
    • Dragonflow – Neutron Done the SDN Way
    • Deploying Neutron Provider Networking on Top of a L3 Provider Network Using BGP-EVPN
    • Overstock.com’s OpenStack Networking Strategy
  • 功能与工具
    • Tap-As-A-Service What You Need to Know Now
    • Skydive, Real-Time Network Topology and Protocol Analyzer
    • Neutron DSCP Policing your Network
    • Troubleshoot Cloud Networking Like a Pro
    • Load Balancing as a Service, Mitaka and Beyond
    • Tired of Iptables Based Security Groups? Here s How to Gain Trem
    • Integration of Neutron, Nova and Designate: How to Use It and How to Configure It
    • SNAT High Availability Service in Neutron for Distributed Virtual Routers
    • Virtual Routers on Compute Nodes: A (Not So) Irrational Decision?
    • F5 Networks – Technically Speaking..Are You in or Are You Out?
  • 开发
    • Understanding ML2 Port Binding
    • Deep Dive into Neutron Upgrade Story
    • Service Function Chaining Technology Analysis and Perspective
    • Case Study Neutron IPAM APIs and External IPAM Integration
    • Neutron Address Scopes
    • Evolving Virtual Networking with IO Visor
    • MidoNet Scalability Testing with Neutron and Open Source Tools
    • Mapping Real Networks to Physical Networks, Segments, and Routed Networks
  • 其他
    • Performance Measuring Tools for the Cloud
    • Project Vitrage How to Organize, Analyze and Visualize your OpeenStack Cloud
    • Intelligent Workload HA in Openstack
    • Senlin Clustering Service Deep Dive
    • Deploy an Elastic, Resilient, Load-Balanced Cluster in 5 Minutes
    • OpenStack Stable
    • Automated Security Hardening with OpenStack-Ansible
    • Open Stack at Carrier Scale
    • Ceilometer, Nova and Neutron – Working Together to Provide a Healthy Network for Your Cloud
    • Distributed NFV & OpenStack Challenges and Potential Solutions
    • Nova Cells V2 What s Going On?
    • Troubleshooting oslo.messaging RabbitMQ issues

前言

此文为目前第一篇 OpenStack Summit 观影指南,笔者在 OpenStack Ausin Summit 期间现场观看了约二十多个 Session,综合之后在 YouTube 上看的一些回放,对 36 个 Session 做了一些介绍和简评,主要集中在网络方面,别的方向一些重要的 Session 也有一些但是不多,为了能让读者看到完整内容,本文主要介绍了在 YouTube 上有完整视频的 Session(Presentation/Keynote 均有完整视频,详见:https://www.youtube.com/user/OpenStackFoundation/videos,在 Youtube 上搜索对应名字即可),对于重要的技术也可能有超出 Presentation 之外的评论,希望能给想用较少时间对 Austin Summit 有所了解的同学有所帮助。

架构

Practical OVN Architecture, Deployment, and Scale of OpenStack

评分:4/5
简介:开头科普了一下 OVN 的架构,一些做的不错的地方,然后着重介绍了这个 Release Cycle 中社区对 Scale 的进展和测试,以及其他一些目标。对 OVN 感兴趣的同学应该看一看。
QQ20160501-2.png-275.4kB
评论
标题虽叫 Practical,但遗憾的是实践的内容并不多,提到了社区做的 Scale 测试,主要是利用 Sandbox 在 20 台物理机上做 2000 个 Hypyervisor 的控制平面模拟,IBM 在实际物理环境中部署过 90 个 Hypervisor 的 Scale,下一步要测试 300 台和 700 台的规模。

关于最近的进展,Scale 上有一定提升,例如 ovsdb-nb 和 ovsdb-sb 分拆到两个进程等,但遗憾的是比较受人关注的 ovsdb 的多进程还在开发中,原生 NAT、摆脱 MQ 等一些关键 Feature 也还没有做完。部署上已经支持了 Puppet OpenStack,同时社区对 Rolling Upgrades 也比较重视,这方面做的也不错。下一步的目标主要还是 OVSDB 的 HA(关键 Feature)、L3 Gateway 和 NAT 的支持(关键 Feature)、Native 的 DHCP、MetaData 等等,还有一段路要走啊。

OVN 刚推出很多人看好,原因最主要是强大的社区,其次刚开始给出的设计文档也不错,遗憾的是刚拿出来的版本距离长期设计目标就差的很远(OVSDB 的 HA 问题,甚至目前还是单进程的!大量的非分布式实现等等),所以就让很多人忧虑 OVN 是不是太晚了,一年多过去了,OVN 社区确实做出了很多努力,但遗憾的是前有 DragonFlow,后有 OpenDaylight OVSDB Netvirt 各种竞争,而且前者发展时间长、已有部署案例,后者在 HA、各种功能(SFC、VxLAN Gateway 等)也有所擅长,而且两者对如何解决数据库/资源同步问题都提出了自己的方案(versioned object、async sync)等,而 ovn 社区目前还没有考虑过这个问题,只能说留给 ovn 的时间已经不多了啊。

OpenStack and Opendaylight The Current Status and Future Direction

评分:4.5/5
简介:开头科普了一下 OpenDaylight 的架构,然后介绍了在 OS M 版和 ODL Beryllium 版上的进展,特别是 V2 版 Driver 的情况,值得一看。
评论
V2 Driver 是一个关键性但复杂的事情,主要是增强了 HA 和 Scalability,这也得益于 OPNFV 的不断测试。其中的关键问题之一是数据库的不同步。做过类似 SDN 与 OpenStack 对接的开发者都知道,因为事涉两个系统,两个数据库,所以保持数据一致性是一个很麻烦但有很重要的问题,一旦处理不好,轻则状态不一致,重则大量脏数据充斥两个系统还无法轻易删除,最终无法维护。ODL 选择了一个相对简单一些的方案,就是将一个 Sync 操作拆开,拆一部分为独立的循环,这个思路可能是和以前的 Neutron agent 学的?

QQ20160501-3.png-231.8kB

我们可以看到 API 返回过程实际是没变的,仍然是直接写数据库然后就返回,但此时状态时 Pending 的,由另一个独立线程周期去取 Pending 的数据,然后交给 ODL,这样来保证 API 操作的即时性和状态的一致性。

轻量测试框架看起来对用户不会有很大的影响,但是对开发真会方便很多,跑和 OpenStack 的集成测试不需要专门跑 ODL 了,简化很多。支持了基于 Port binding 的 OVS DPDK 集成(这样你可以混布 DPDK 和 非 DPDK 了!),100% 通过 Tempest 测试。在新版的 ODL 上,HA、稳定性、各种 Feature 也增强很多,可以认为 ODL 和 OpenStack 集成已经很靠谱了。

在下一个版本中,一方面是 v2 的继续增强,一方面是 SFC、FD.io、BGPVPN、L2GW 等这些的增强。按照 FD.io 的文档,FD.io 社区的计划也是通过 ODL 与 OpenStack 集成,按照目前的资料 FD.io 的性能特别是多流性能上就超出 OVS DPDK 一大截,值得期待。SFC 有其他 Session 做介绍,这里就不多说了。最后做一点科普,OpenDaylight 可以作为纯软的 OpenStack SDN 后端,具体的模块是 netvirt,也是以 OVSDB 来控制 OVS 完成网络功能,目前功能的完善程度还是比较高的。

Read More →

Netfilter 为每种网络协议定义了一套钩子;

  • 内核的任何模块可以对每种协议的一个或多个钩子进行注册;
  • 排队的数据包被传递给用户空间并异步进行处理。

钩子点

  1. pre_routing:路由查找前,ip_recv(),在此之前,只简单检查协议版本号、包长度、检验和等
  2. local_in:目的地址为本机的数据包,ip_local_deliver()
  3. forward:经过防火墙转发、目的地址非本机,ip_forward()
  4. post_routing:最终送入物理介质前,适合snat或统计
  5. local_out:本机产生并发送的包

以上几个钩子位置如图(wei: ip_fragments 现在应该是ip_fragment 吧):

LinuxNet1

注册的钩子函数都将返回下列返回值之一(wei:定义于include/uapi/linux/netfilter.h):

  1. NF_ACCEPT:接受并递交;
  2. NF_DROP:完全丢弃;
  3. NF_STOLEN:钩子将对数据包开始处理,Netfilter放弃该数据包的所有权
  4. NF_QUEUE:包发往用户空间,等待用户空间程序处理
  5. NF_REPEAT:请求Netfilter再次调用这个钩子

wei代码里还可以看到还有 NF_STOP,看介绍是接受并阻止后面的钩子继续处理)

 

Netfilter 的内置功能模块有系统初始化配置脚本加载到内核,再由内核自动调用,各模块功能相互独立,如 Filter 在需要过滤控制时加载,NAT 在需要NAT时加载。注册中比较重要的数据结构是 nf_hook_ops ,注册和卸载分别调用 nf_regerister_hook() nf_unregerister_hook() 函数。

nf_hooks 是一个二维数组 nf_hooks[NPROTO][NF_MAX_HOOKS] NPROTO 表示当前内核允许的最大协议数,(wei:位于uapi/linux/net.h#define NPROTO AF_MAXAF_MAX 目前为41,具体见 include/linux/socket.h PF_**,与 AF_** 一致,其中 local UNIXROUTE NETLINK),NF_MAX_HOOKS 表示对任一协议组需要用的钩子的最大数目。其类型是 list_head,可以理解为双向链表,(wei:它有一个变量属性是 __read_mostly,这个是gcc自己实现的语法,可以参考这里:https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Variable-Attributes.html,在这里目的为放入cache中,关于 list_head 的使用可以看这里:http://oss.org.cn/kernel-book/ldd3/ch11s05.html

nf_hook_ops 其定义在 include/linux/netfilter.h

struct nf_hook_ops {
    struct list_head list;

    /* User fills in from here down. */
    nf_hookfn   *hook;
    struct module   *owner;
    void        *priv;
    u_int8_t    pf;
    unsigned int    hooknum;
    /* Hooks are ordered in ascending priority. */
    int     priority;
};

其中,list 是链表指针,hook 是钩子函数指针,其格式格式为 nf_hookfn

typedef unsigned int nf_hookfn(const struct nf_hook_ops *ops,
                   struct sk_buff *skb,
                   const struct nf_hook_state *state);

 
struct nf_hook_state {
    unsigned int hook;
    int thresh;
    u_int8_t pf;
    struct net_device *in;
    struct net_device *out;
    struct sock *sk;
    int (*okfn)(struct sock *, struct sk_buff *);
};

hooknum 表示钩子函数挂在哪个钩子点上,如 NF_IP_PRE_ROUTING 等,定义于uapi/linux/netfilter_ipv4.h

 priority 表示优先级,数字越小优先级越高。

 

钩子的注册主要依赖 nf_register_hook() 函数:

int nf_register_hook(struct nf_hook_ops *reg)
{
    struct nf_hook_ops *elem;
 
    mutex_lock(&nf_hook_mutex); //互斥锁
    list_for_each_entry(elem, &nf_hooks[reg->pf][reg->hooknum], list) {
        if (reg->priority < elem->priority)
            break;
    } //宏,用于遍历链表
    list_add_rcu(&reg->list, elem->list.prev); //把链表项插入到RCU保护的链表elem->list.prev的开头
    mutex_unlock(&nf_hook_mutex);

#ifdef HAVE_JUMP_LABEL
    static_key_slow_inc(&nf_hooks_needed[reg->pf][reg->hooknum]);
#endif

    return 0;
}

  Read More →