现场回顾

故事发生于某个下午,采用 salt 更新某集群的 neutron.conf (log 相关配置项) 并批量重启 neutron-openvswitch-agent(以下简称 neutron-ovs-agent),不久便有人反馈云主机宕机。

立即排查发现云主机并没有宕机,只是网络不通,大部分计算节点的 ovs 流表空空如也。Nova 和 Neutron 打出 ERROR 级别的日志。

$ ovs-ofctl dump-flows br-bond
NXST_FLOW repy (xid=0x4) cookies=0x0, duration=433.691s, table=0, n_packages=568733, n_bytes=113547542, idle_age=0, priority=1 actions=NORMAL cookies=0x0, duration=432.358s, table=0, n_packages=8418, n_bytes=356703, idle_age=0, priority=2, in_port=3 actions=drop

neutron-ovs-agent Log:

DeviceListRetrievalError: Unable to retrieve port details for devices because of error: Remote error: TimeoutError QueuePool limit of size 10 overflow 20 reached, connection timed out, timeout 10

neutron-server Log:

File "/usr/lib64/python2.6/site-packages/sqlalchemy/pool.py", ... 'TimeoutError: QueuePool limit of size 10 overflow 20 reached, connection timed out, timeout 10\n'

nova Log:

NeutronClientException: Request Failed: internal server error while processing your request.

上述信息可得出以下结论:

  • Neutron 日志表明 neutron-ovs-agent 通过 rpc 向 neutron-server 请求虚拟机 port 相关信息失败,失败的原因是 neutron-server 和数据库的连接数超出连接池的上限。
  • Nova 日志表明 neutron-server 无法响应 HTTP 请求。
  • 被清空的 ovs 流表导致虚拟机的网络瘫痪。

导火索

深入剖析之前,先了解该 Icehouse 集群的基本信息:该集群有 102 个计算节点,运行着 nova, neutron, glance,ceilometer 等服务,为了避免单点故障,我们去除了 neutron l3 等相关服务,采用大二层的网络,虚拟机通过物理路由与外界通信。理论上说,无论哪个服务异常,甚至任意节点宕机,最差的结果是 openstack 服务不可用或者少量虚拟机故障,但绝大部分虚拟机依旧能正常运行。

经验告知,采用以上网络模型的多个集群一年多以来从未发生如此规模的故障。由于 log 模块配置项不会影响流表,直觉上推测批量重启可能是触发 ovs 流表被清空的导火索。


Neutron 的一个坑

由于流表被清空前仅仅重启了 neutron-openvs-agent,而计算节点,仅仅只有 neutron-ovs-agent 与 ovs 有交互,故按图索骥的浏览 neutron-ovs-agent 重启流程,梳理其逻辑如下:

  1. 清除所有流表
  2. 通过 rpc 向 neutron-server 获取流表相关信息
  3. 创建新流变

不难发现,如果步骤 2 异常,比如 neutron-server 繁忙,消息中间件异常和数据库异常等种种因素,都会影响流表的重建,重则导致虚拟机网络瘫痪。事实上,社区也意识到了类似的问题:重启 neutron-ovs-agent 会导致网络暂时中断。

Restarting neutron ovs agent causes network hiccup by throwing away all flows

社区的处理方式是增加配置项 drop_flows_on_start,默认其值为 False,从而避免上述问题。该 Patch 已合入 Liberty,梳理其重启的逻辑流程如下:

  1. 用一个 cookie 标志当前流表
  2. 获取新流变并更新至 ovs
  3. 根据 cookie 清除旧流表

neutron-ovs-agent 在重启的过程中就流表的处理留下了一个隐患,直接的后果就是导致计算节点的流表被清理的干干净净,虚拟机成一个个孤立的点,而多种因素可触发该隐患。


最大连接数

现在解释为什么批量重启 neutron-ovs-agent 会触发上述隐患,重启过程中,neutron 日志报出如下错误:

'TimeoutError: QueuePool limit of size 10 overflow 20 reached, connection timed out, timeout。

这条日志意味着 neutron-server 和数据库的连接数超出客户端连接池的上限,当 neutron-ovs-agent 批量重启时,上百并发的通过 rpc 向 neutron-server 请求构建流表的相关信息,neutron-server 和数据库的连接数也就远远超过 30,造成大量的请求失败,计算节点获取不到流表相关信息无法重建流表,故计算节点的流表为空。

要解决因 QueuePool 的限制而引起的 TimeoutError 问题也很简单,sqlalchemy 提供了两个配置项[1],把下面两个参数适当调大即可。

[database]
max_overflow =
max_pool_size =

Note: MySQL server 默认最大连接数为 100,当集群的规模上升时,需适当调整 MySQL server 最大连接数。


进程的性能问题

然而问题并没有完全解决,请注意 nova 的错误日志:

nova.compute.manager NeutronClientException: Request Failed: internal server error while processing your request.

这是nova 发给 neutron-server 的一条 HTTP 请求,neutron 返回了 internal server error。Internal server error 对应的 HTTP status code 为 500,意味着 neutron-server 无法响应 nova 请求。为什么会无法响应呢,批量重启的过程中,发现 neutron-server 进程的 CPU 使用率为 100 %,意味着 neutron-server 正忙于处理 neutron-ovs-agent 大量的请求,因而无暇处理 nova 的 HTTP 请求。

解决该问题的方法同样很简答,增加更多的 neutron-server 进程数即可。事实上,因 nova-conductor 要处理 nova-compute 大量的 rpc 请求(nova-compute 通过 nova-conductor 访问数据库),自 Icehouse 起,nova-conductor 就默认启动了多个进程,进程的数目等同服务器 CPU 的逻辑核数。

$ workers=`cat /proc/cpuinfo |grep processor |wc | awk '{print $1}'`

[DEFAULT]
api_workers = $workers
rpc_workers = $workers


Python 的并发 & IO

值得思考的是,对双路 12 核共 24 线程的服务器来说,数百并发请求真的算高么?neutron-server 进程的 CPU 最大使用率只能到达 100 %,意味着 neutron-server 仅仅利用了服务器的一个线程。这里不得不提协程(crontine)[2],这种伪并发的“用户态线程” 意味着任意时刻只有一个协程在执行,即任意时刻只能利用服务器 CPU 的一个线程,而 openstack 所有组件的进程里满满都是协程(只有一个主线程),因而单个进程下,neutron-server 不能充分利用多核的优势以提高处理并发的能力。

传统的 web 服务器 apache 和 nginx 利用多进程多线程提高并发数(上下文切换的开销:进程 > 线程 > 协程)。那么问题来了,单进程条件下,是不是可以用线程替换协程从而提高 neutron 的并发能力呢?真实的答案是 No, 根本原因在于 python GIL[3],俗称 python 全局锁。对于 python 的程序来说,单进程只能在任何时刻只能占用一个物理线程,所有只有多进程才能充分利用服务器的多核多线程。

让我们深入一点,假设的 CPU 足够强大,是不是可以解决 neutron-server 单进程的并发问题呢?我觉得未必,这又回到了 IO 问题。Monkey patch[4] 虽然把系统的 socket 库替换成自己提供的非阻塞 socket 库,从而避免某些阻塞 IO 阻塞了整个进程(主线程)。但是 OpenStack 访问 MySQL 使用的是 libmysqlclient 库,eventlet 并不能对这个使用了系统 socket 的 C 库使用 monky_patch,所以对 MySQL CRUD 的时候会阻塞主线程,意味着 neutron-server 在访问数据库也容易出现性能瓶颈。

解决上诉并发问题的方法之一就是启动更多的 api worker 和 rpc worker。在较新的版本,OpenStack 默认的 wokers 就是服务器的逻辑核数。另外一种办法是用 apache 替换 python http server,最近各个组件逐步提供了对 apache 的支持。


Reference

    1. http://docs.sqlalchemy.org/en/rel_0_9/core/pooling.html
    2. http://www.dabeaz.com/coroutines/Coroutines.pdf
    3. http://stackoverflow.com/questions/1294382/what-is-a-global-interpreter-lock-gil
    4. http://stackoverflow.com/questions/11977270/monkey-patching-in-python-when-we-need-it

http://wsfdl.com/openstack/2015/10/10/%E4%B8%80%E6%AC%A1%E6%89%B9%E9%87%8F%E9%87%8D%E5%90%AF%E5%BC%95%E5%8F%91%E7%9A%84Neutron%E7%BD%91%E7%BB%9C%E6%95%85%E9%9A%9C.html

(转) 一次批量重启引发的Neutron网络故障的更多相关文章

  1. CentOS7安装OpenStack(Rocky版)-06.安装Neutron网络服务(控制节点)

    上一章介绍了独立的nova计算节点的安装方法,本章分享openstack的网络服务neutron的安装配制方法 ------------------- 完美的分割线 ----------------- ...

  2. 云计算之路-阿里云上:启用Windows虚拟内存引发的CPU 100%故障

    今天上午11:35~11:40左右,由于负载均衡中的两台云服务器CPU占用突然飚至100%,造成网站5分钟左右不能正常访问,请大家带来了麻烦,请谅解! (上图中红色曲线表示CPU占用) 经过分析,我们 ...

  3. openstack——neutron网络服务

    一.neutron 介绍:   Neutron 概述 传统的网络管理方式很大程度上依赖于管理员手工配置和维护各种网络硬件设备:而云环境下的网络已经变得非常复杂,特别是在多租户场景里,用户随时都可能需要 ...

  4. OpenStack核心组件-neutron网络服务

    1. neutron 介绍 1.1 Neutron 概述 传统的网络管理方式很大程度上依赖于管理员手工配置和维护各种网络硬件设备:而云环境下的网络已经变得非常复杂,特别是在多租户场景里,用户随时都可能 ...

  5. 启用 SR-IOV 解决 Neutron 网络 I/O 性能瓶颈

    目录 文章目录 目录 前言 Neutron 的网络实现模型 基于虚拟网络设备的虚拟机流量走向 Neutron 网络实现模型的性能瓶颈 SR-IOV 技术简介 在 Neutron 中引入 SR-IOV ...

  6. neutron网络服务部署

    控制节点执行 #第一步 登陆数据库 mysql -u root -p #导入neutron这个库 CREATE DATABASE neutron; #创建neutron这个用户和密码,并允许本地登陆和 ...

  7. Neutron网络-OPENSTACK讲得比较透和方便

    http://www.ustack.com/blog/neutron_intro/ Neutron是OpenStack核心项目之一,提供云计算环境下的虚拟网络功能.Neutron的功能日益强大,并在H ...

  8. Neutron网络性能测试与分析(一) CVR

    测试环境:网络节点运行在Intel(R) Xeon(R) CPU E5-2630 v3服务器上,网卡使用intel的万兆卡82599ES 测试仪使用本人基于dpdk编写的程序,基本上可以打满万兆卡,小 ...

  9. openstack第四章:neutron— 网络服务

    第四篇neutron— 网络服务 一.neutron 介绍:   Neutron 概述 传统的网络管理方式很大程度上依赖于管理员手工配置和维护各种网络硬件设备:而云环境下的网络已经变得非常复杂,特别是 ...

随机推荐

  1. NSCache类的简单介绍

    最近看SDWebImage,里面的内存缓存用到了NSCache这个类,由于以前没有使用过,特此记录学习一下. NSCache NSCache是苹果官方提供的缓存类,用法和NSMutableDicton ...

  2. mono下c#和c交互,字符串处理

    起因是ulua里,从luajit读字符串到c#里,做了编码转换,如下 public static string lua_tostring(IntPtr luaState, int index) { v ...

  3. Python函数参数默认值的陷阱和原理深究(转)

    add by zhj: 在Python文档中清楚的说明了默认参数是怎么工作的,如下 "Default parameter values are evaluated when the func ...

  4. Datetime 模块求日期差

    Datetime 模块求日期差 导入 datetime 模块/实例化当前时间对象 调用.date() 方法 得到当前年/月/日时间 实例化时间差对象 delta 求当前日期减去时间差 delta 后的 ...

  5. Thrift官方安装手册(译)

    本篇是Thrift官网安装文档的翻译,原地址点击这里.Thrift之前是不支持Windows的.但是似乎0.9版本以后已经支持Window了.介绍了Thrift安装的环境要求以及在centos,Deb ...

  6. golang接收get/post请求并返回json数据

    // @router /d2 [post] func (c *MainController) D2() { // jsoninfo := c.GetString("ok") // ...

  7. 005-搭建框架-实现AOP机制【二】AOP技术

    一.什么是AOP aspect-oriented  programming,面向切面编程,对oop的一种补充. 著名示例,aspectj,spring+aspectj 二.aop之代码重构 2.1.代 ...

  8. Java基础—反射(转载)

    转载自: JAVA反射与注解 JAVA反射 主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义. 反射机制是什么 反射 ...

  9. ABAP锁,数据库锁

    原文出自 江正军 技术博客,博客链接:www.cnblogs.com/jiangzhengjun ABAP数据锁定 SM12锁查看与维护 通用加锁与解锁函数 ABAP程序锁定 数据库锁 锁的分类和兼容 ...

  10. Python基础-序列化(json/pickle)

    我们把对象(变量)从内存中变成可存储的过程称之为序列化,比如XML,在Python中叫pickling,在其他语言中也被称之为serialization,marshalling,flattening等 ...