使用kubeasz快速搭建k8s集群all-in-one开发测试环境

最近在为VisionStack产品开发容器服务,提起容器服务就不得不考虑kubernetes项目(简称k8s),当今主流开源的容器编排框架,因此就想搭建一个k8s环境调研下它的功能、使用、相关概念等内容,在搭建环境过程中,首先是参考官网文档提到的minikube工具,用它来进行测试环境的搭建,结果折腾了一下午,也没有成功,遇到的最大问题是国内的防火墙屏蔽了google相关网站的访问,而k8s是google主推的,大部分资源都在google服务器上(如环境部署过程中用到的各种docker镜像都需要从gcr.io上下载,这个是google云提供的docker镜像库网站),如果镜像都无法下载,那肯定环境也就无法搭建成功了。而另外一个工具kubeadm,由于比较复杂,另外估计很可能也会遇到类似问题,也就没有尝试。

正准备放弃的时候,发了个朋友圈吐槽这个事情,正好有朋友也遇到过这个问题,他推荐了另外一个工具:kubeasz,专门针对国内网络环境开发的k8s安装部署工具。下面的安装部署过程就是基于它来完成的,并且是一次成功,对搭建开发测试环境来说非常简单易用,因此这里强烈推荐下(这个故事告诉我们,朋友圈真的是万能的)。下面的安装过程也主要是参考它给的官方文档,略有删减。

项目地址:https://github.com/gjmzj/kubeasz

项目用途:使用Ansible脚本安装K8S集群,介绍组件交互原理,方便直接,不受国内网络环境影响。

快速指南

以下为快速体验k8s集群的测试、开发环境all-in-one部署,国内环境下觉得比官方的minikube方便、简单很多。

1.基础系统配置

  • 推荐内存2G/硬盘20G以上
  • 最小化安装Ubuntu 16.04 server或者CentOS 7 Minimal
  • 配置基础网络、更新源、SSH登陆等

2.安装依赖工具

我实验过程中使用的是CentOS 7.2系统。

Ubuntu 16.04 请执行以下脚本:

CentOS 7 请执行以下脚本:

3.ansible安装及准备

4.安装kubernetes集群

如果执行成功,k8s集群就安装好了。详细分步讲解请查看项目目录 /docs 下相关文档

5.验证安装

6.安装主要组件

7.dashboard安装及登录

  • 登陆 dashboard可以查看和管理集群,更多内容请查阅dashboard文档
  • 本文档基于 dashboard 1.8.3版本,k8s版本v1.10.0。

7.1部署dashboard

如果之前已按照本项目部署dashboard1.6.3,先删除旧版本:kubectl delete -f /etc/ansible/manifests/dashboard/1.6.3/

1.8.3配置文件参考官方文档

  • 增加了通过api-server方式访问dashboard
  • 增加了NodePort方式暴露服务,这样集群外部可以使用 https://NodeIP:NodePort (注意是https不是http,区别于1.6.3版本) 直接访问 dashboard,生产环境建议关闭该访问途径。

安装部署

7.2验证部署结果

7.3登录dashboard

访问 https://x.x.x.x:8443/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy (该URL具体使用kubectl cluster-info|grep dashboard查看) ,先使用admin、test1234账号密码通过http认证,之后选择令牌方式登录,令牌通过命令行kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep admin-user | awk '{print $1}')获取(token:那行),复制冒号后的全部字符并粘贴到dashboard‘输入令牌’处即可。admin登陆拥有所有权限,比如删除某个部署;使用 readonly登陆只有查看权限,尝试删除某个部署会提示错误 forbidden: User \"readonly\" cannot delete services/proxy in the namespace \"kube-system\"

8.清理集群

以上步骤创建的K8S开发测试环境请尽情折腾,碰到错误尽量通过查看日志、上网搜索、提交issues等方式解决;当然如果是彻底奔溃了,可以清理集群后重新创建。

一步清理:ansible-playbook 99.clean.yml

总结

上述流程大部分都是由工具自动完成的,并且所需要的资源也已经全部下载到本地,因此安装过程其实很快,如果你也有类似需求,可以试试这个工具。

参考资料

Apache+WSGI中文文件名导致HTTP请求返回500问题解决方法

问题症状

Centos7服务器上搭建了Apache服务,版本httpd-2.4.6-67.el7.centos.6.x86_64,配合mod_wsgi+python+flask搭建web网站。

用flask的render_template渲染html页面,并且用配置文件里的文件名和路径来生成文件下载链接,如果文件路径包含中文,会在请求页面时返回500响应码,而python main.py前台启动没有这个问题,改成英文文件名后Apache+WSGI启动方式也恢复正常。

相关代码如下所示:

解决方法

网上搜到很多方法都是说修改/etc/apache2/envvars文件,但新版本Apache已经没这个文件了,折腾了好久都没进展,偶然看了下Apache的systemd的启动脚本/usr/lib/systemd/system/httpd.service,发现里面有个EnvironmentFile配置项:

原来是在这里配置的,尝试把原来的LANG=C改成上面两行,之后重启Apache服务,再访问出问题的页面,一切正常了,问题解决。

基于云主机+docker engine的容器服务

在基于kubernetes实现容器编排产品之前,我们基于现有的VisionStack云平台,利用云主机+docker engine+自研编排服务+私有镜像仓库的方式,实现了一套自己的容器服务,方便用户基于docker镜像来发布和管理业务。

后续我们也会考虑基于kubernetes研发一套真正意义上的容器编排产品,这个产品应该是独立于现有的VisionStack产品之外的一套新系统。

名词说明

服务:对应业务产品,通常一个产品可以创建一个服务(如果有需要的话,一个产品的不同版本也可对应多个服务)

节点:服务的基础,业务容器化首先需要创建云主机(容器跑在云主机上),一个服务可以创建多个云主机便于高可用及业务升级

副本:第一期的版本,每个节点只启一个容器,后续考虑完善,每个节点启多个容器来部署服务,一个容器即为一个副本

容器镜像:用户根据自己的业务环境制作的容器镜像,可以满足业务产品的运行,用户需要自己上传到镜像仓库

负载均衡权重:每个服务对应一个负载均衡,来实现对于各个节点服务的访问,权重可以控制访问频率。权重是相对来说的,权重越高的节点被访问的频率越高

本次功能添加如图所示:

导航栏添加容器服务,并为其添加两个子项——服务列表、镜像仓库

镜像仓库

镜像仓库是容器服务功能的基础,我们搭建了自己的私有仓库并提供筛选和删除功能。用户使用该功能之前,首先需要自作自己的业务docker镜像,并将其push到私有仓库,以便后续的使用。上传的镜像主要支持名称及版本,满足升级和管理。

服务列表

服务列表是该项功能的主要操作页面,大部分的功能点集中在这个页面。

一、服务列表

服务列表包括信息如图:名称、对外提供的ip及端口、节点数(每个节点为一台云主机,目前采用的实现方式是,一个节点启一个容器;后续会进一步完善为一个节点多个容器)、规格(为所有节点的规格,现在所有节点规格相同,后续会考虑支持不同的节点对应不同的规格)、状态(展示该项服务的健康状况,便于监控)

二、创建服务

我们可以把某项业务部署创建为一项服务,以便于管理和部署。创建之前,需要用户将自己的业务制作为容器镜像,并上传到私有镜像仓库,创建页面如下:

如图所示,创建过程中我们首先需要填写自己的服务名称,并设置服务端口号和节点数(目前支持1-10个节点);可用域和物理机需要多选,单选的话无法支持高可用(高可用需要多节点多物理机);节点(云主机)创建需要用户名密码、主机规格、网络、安全组等参数(参考创建云主机);创建服务最重要的就是选择自己的容器镜像,目前提供镜像及镜像版本的选择(如果愿意的话,你可以将某项业务部署多个版本);负载均衡用于对外提供可以访问的ip及端口。

三、修改服务

当前修改功能比较简单,当前仅支持修改服务名称和节点数。修改弹框如图:

四、删除服务

提供删除服务的功能,当前删除时彻底删除,后续考虑提供回收站及 删除防误

五、服务升级

服务升级是我们的重点,当前提供3种升级方式:滚动发布、停服发布、手动发布。

1、滚动发布

滚动发布可向后滚动(产品升级),也可以向前滚动(产品回滚),该项发布为自动发布,只需选择镜像及版本,就可以完成升级工作。页面如下:

2、停服发布

停服服务可以理解为滚动发布的简化,也支持向后滚动(产品升级)、向前滚动(产品回滚)。其与滚动发布的唯一区别就是滚动发布不需停服(会出现极短时间的新老版本共存的情况),停服发布需要停服。页面如下:

3、手动发布

手动发布适用于测试不充分或者需要在生产环境补充测试的业务发布(可在升级过程中进行测试),页面如图:

该升级功能可选镜像和节点,每个节点后标注镜像、版本和负载均衡权重,手动升级可以分N次,每次可选M(M<=8, M=8时为手动停服发布)个节点进行升级。勾选服务,打开弹框,选择手动发布,弹框中显示节点列表(节点包括镜像版本和负载均衡权重,权重为0时表示该节点在负载均衡服务中处于禁用状态)。下拉选择镜像及版本,勾选想要升级或回滚的镜像,若不需要测试,可配置负载均衡权重为非0,直接将选中的节点升级。若需要测试则勾选选镜像、节点并将勾选节点的权重置为0,点击确定,此时服务列表中该服务及该服务的节点列表状态显示升级中。发布人员可以在此时进行测试,若测试成功,可以再次勾选该服务,选择手动发布,将新升级的节点负载均衡权重置为非0(因为当前每个节点的规格相同,所以建议完成升级之后把每个节点的权重设为相同的值)。当全部节点中只升级了一部分,此时该服务包括新老两个发布版本的产品,若为了谨慎发布可以将新升级的节点负载权重配小,待产品稳定后可以再将权重全部保持一致。当然用户也可以自己随意设置自己的各个节点的权重。

六、导出excel及自定义列表功能

这两个功能和产品的其他页面一致

七、详情

详情用于展示某项服务的详细信息,目前展示信息如下图所示,后面可以考虑继续完善。

八、节点列表

勾选某项服务,点击节点列表按钮可进入节点列表子页面:

列表中展示的内容如图所示,功能包括添加/删除节点、控制台、导出excel、自定义列表。

控制台提供登录Docker所在节点(云主机)的入口。

九、副本列表(当前未做)

当前每个节点只包含一个容器,后面考虑完善功能,在一个节点启多个容器(副本),这时就需要副本列表页面。

 

写给儿子们<17>

这两天小区里的家长们在讨论民办小学报名的事情,有些还去报了名,录取的也有(虽然最终也没交钱确认入学)

关于这件事情,你们的妈妈想法跟爸爸的又有一些差别

你们的妈妈想让你们报名,试试看,能行就去上

而爸爸则不打算去

原因有如下几个:

  1. 学费比较贵(便宜的一万多每学期,贵的5万,这还是明面上的费用,其他的算下来每年估计也得再翻倍),即使我们家能拿得出来这么多钱,我也更愿意花钱在别的投资上(比如买房、做生意)
  2. 离家太远,接送太折磨人(包括大人小孩)
  3. 爸爸从内心深处还是觉得小学阶段不是那么重要,初高中尤其是高中才是最重要的,这也是爸爸的切身体会(当然有些家长认为小学是基础,基础都不好以后肯定上不了好初中、高中)
  4. 你们奶奶可以给你们辅导,小学阶段应该不用发愁

上述原因我第一条和第三条我得深入解释下,比如第一条,宁愿花钱在投资上也不愿意让你们读一年20万(5万的太远,20万的太贵)的私立学校,为啥这么想?不重视孩子的教育吗?

我觉得我是没有重视到着魔的程度,但也没有轻视到忽略的地步。只能说是在我们家现有条件下,尽力做到最好。

为啥要投资别的方面而不是给你们读私立?因为从爸爸目前具有的人生经验来说,学历不是万能的,即使你们都考上北大清华,毕业后最多还是进一家顶尖企业(当然出国留学甚至移民之类的这里没考虑,这条路我没走过,也不敢乱说,但我估计也没那么轻松),然后当一个高级白领(当然金领也有可能,但希望不大),起早贪黑,加班严重,生活压力巨大,相比一个有N套房的拆迁户来说,还是屌丝一个,还是不敢吃不敢穿不敢消费,生活质量也不会高到哪里去。曾经有一篇文章让我感触很深,说的是上海税前一个月拿3W房贷车贷1W多的高级白领和公司里有N套房的拆迁户清洁大妈,那一个生活质量更高?哪一个更幸福?我觉得大部分都会毫不犹豫的选后者。当然拆迁户不常有,拿做生意或者投资房产来比较会更合适。如果爸爸赚了大钱,每人给你们在一线城市留下5套房子(爸爸的10套房目标的来源),哪怕是小户型,只要你们不乱搞不败家,保证你们一辈子都可以衣食无忧,不用担心生计问题,上班嘛也就成了体验生活的一项爱好或者兴趣了,奋斗或者创业起来也更有底气(有保底生活来源,不用惧怕失败),心情不好可以随时炒老板鱿鱼,可以做到世界那么大、随时去看看。

你们的妈妈则老说,不用给孩子们留那么多钱、房子,让他们自己赚去,什么都给他们准备好了,就没有奋斗的动力了。其实爸爸也不是完全没有这种想法,爸爸和妈妈也是这么过来的(当然你们的爷爷奶奶和姥姥姥爷也帮衬了我们一些,但也只是有限的一部分),但如果我们能多准备点,你们的人生起点不是更高一些吗?

关于第三条原因,爸爸是基于自己的人生经历来考虑的,爸爸在小学、初中、甚至高中的成绩来说都是中等,偶尔偏上一些,但爸爸从来没有放弃过,一直在努力往前进,也就是人们常说的上进心比较强。有些同学原本成绩很优秀,但到了初中、高中阶段就不学了,去打游戏、上网、看小说、谈恋爱等等,转移了方向,不再以学习为主了,自然就落后了(当然并不是说学习不好就没有前途,恰恰相反,有些成绩不怎么好的同学反而赚钱更多,活的更潇洒),爸爸这里想表达的意思是,在人生的每个阶段都有该做的事情,初中高中阶段肯定是以学习知识为主题,其他的事情都是附带的边角料,适当的了解下也没问题,算是拓展视野,丰富人生阅历,但千万不能转移了大主题。还有些同学千辛万苦考上了大学,在学校里醉生梦死、无所事事,连考试都科科必挂,最终毕业证、学位证一个都没拿到,而爸爸则由于担心找不到工作,只得硬着头皮继续考研,虽然也没考上什么好学校,至少可以让爸爸毕业后能有一份工作,能养家糊口了。任何时候都不能放弃奋斗,除非你的人生追求不在于此,享受人生也得等到正确的时间,没有物质基础的享受是不可能长久的。

一直以来爸爸对你们的希望都只有两点最重要:平安,健康。其他的方面都是补充或者说点缀,属于有了更好的那种性质。

有些人常说:条条大路通罗马,但有些孩子就出生在罗马。爸爸妈妈没能让你们生在罗马,但至少我们在努力的带着你们往罗马的方向慢慢前进。

 

写给儿子们<16>

上周末过完清明假期,你们的妈妈开始上班了

为啥要提这事儿?

1是因为她去上班的地方很远,歙县,200多公里,开车要2个半小时

2是因为她不想去那么远的地方上班,但还是去了,为啥呢?

妈妈生弟弟之前就在这家工厂上班,生完弟弟工厂搬走了,搬到了现在的地方

妈妈带着弟弟和姥姥去了那边,舅舅也在那边打工,姥姥照看弟弟,妈妈上班

爷爷带着哥哥在家,负责接送上学、做饭

妈妈估计要一两周甚至个把月才能回家一次,弟弟去了吃东西也不方便

 

你们妈妈说去那边上班是爸爸伤了她的心,是爸爸想让她去,不然她都不想去

至于为啥她会这么想,我也没搞太清楚,简单跟她沟通了下,可能是有下面几个原因:

  1. 妈妈说爸爸曾在各个场合跟多个亲人表示她要去那边上班,需要人过来帮忙照顾弟弟,这样姥姥才愿意从老家过来的
  2. 妈妈认为爸爸不想让她在家,认为爸爸想一个人乐得清净,没人管更自在
  3. 妈妈认为爸爸觉得她不挣钱,所以想让她抓紧挣钱
  4. 妈妈觉得跟爸爸没啥共同语言,在家不在家没啥区别

总体来说,我感觉是妈妈觉得爸爸对她不够好、不够关心、不顾家,只想着赚钱、赚钱、多赚钱,钱都不舍得给她花,她多次说过都不敢跟爸爸要钱花(没有取钱给她花过)。

实际来说,妈妈想的也不完全错,爸爸是有一些地方做的不好,举例来说:

  1. 只想着赚钱、赚钱、多赚钱,忘记了初心(当年爸爸跟妈妈刚订婚的那段时间,经常跟妈妈说咱赚到10万就回郑州付个首付买房结婚,后来目标改成了30万,再后来到现在目标改成了买10套房),让她压力越来越大
  2. 不顾家,对妈妈和家人不够关心(上班经常加班,下班就抱着手机,周末还大小周,再加上周日哥哥兴趣班,基本都没怎么陪妈妈)
  3. 舍不得花钱,太抠门(没给妈妈买过什么东西,也没主动给她过钱)
  4. 沟通交流太少(除了带娃就没啥共同语言了)

实际来说,有些事情我得解释下,主要是缺乏沟通,俩人带娃带的都忘了对方也需要关心、交流、倾诉了。上面这些有些是玩笑话,比如买10套房,估计有生之年都不一定实现得了,只能算是梦想。不顾家这个也是一定程度上存在的,不顾家也是为了多赚钱,或者为了以后多赚钱,或者能赚更长远的钱,提升自己的实力,花了一部分时间在看书学习工作上。爱看手机,这部分也是存在的,上班憋的,下班想放松下,看看新闻、段子啥的,这东西还有点上瘾(游戏啥的早就不玩了),就忽略了妈妈,其实也不是特别多,妈妈自己也有点手机控。抠门这个不得不说,生活习惯就这样,不光爸爸,妈妈也一样,导致生活质量太低,这个真的是没办法,从小养成的习惯或者说毛病,一时半会儿改不了,也不知道买啥搞啥浪漫,在这方面爸爸妈妈俩人谁也别说谁。沟通交流少这个是这样,妈妈有啥事情都不愿意跟爸爸说,可能是爸爸让她觉得说与不说都一样,不会被重视,这点我一定得改掉,多主动跟妈妈沟通交流,少看手机。不过我估计等弟弟再大一些,不用这么费时间照顾,应该就会好一些。

至于说爸爸觉得妈妈不挣钱,爸爸真没这么想。只是跟妈妈说,现在的工厂好歹也有一丁点股份在里面,并且目前工厂发展前景看起来还不错,如果这点股份能有些回报,也是很不错的,并没有勉强的意思,妈妈要是不想去我肯定不会非得让她去。主要还是想着爸爸后面很有可能干不了多久现在的工作,虽然不知道这么想对不对,所以还是想给咱们家留条后路,毕竟还有俩儿子要养,养大你俩还不知道得花多少钱呢,为啥要生你俩呢,哎,看在你俩这么可爱的份上,继续努力挣钱吧。希望你俩长大了可以自己赚钱,赚大钱,让爸爸妈妈也跟着享享福。

妈妈上班的事情先这样吧,跟妈妈说了不要勉强,不想干就回来,赚钱够吃饭的就行,能赚多少算多少,尽力而为。就是妈妈在那边特别想哥哥,还有点愧疚,觉得抛弃了哥哥。

【翻译】RADOS: A Scalable, Reliable Storage Service for Petabyte-scale Storage Clusters

RADOS:Reliable Autonomic Distributed Object Store

论文原文地址:https://ceph.com/wp-content/uploads/2016/08/weil-rados-pdsw07.pdf

翻译动机:看一遍没感觉,看两遍有点理解,翻译出来加上自己的思考才是真的有意义。

摘要

原文翻译略,简单写下自己对这篇论文的理解。

这篇论文主要介绍了RADOS存储系统的原理和设计思路,以及各个组件的用途和一批专用名词的概念,最后大概介绍了后续工作方向。这是一篇学术论文,所以比较格式化。

阅读这篇文章可以学到RADOS存储系统的基本原理和相关概念,配合其他Ceph相关文章或书籍(比如learning ceph)来学习,效果更佳。

1. 简介

对存储系统设计师来说,研发一套高可靠、高性能的存储系统一直都是一个巨大的挑战。文件系统、数据库及其他相关系统依赖的高吞吐、低时延的存储系统是保证各类应用性能的关键基础设施。构建于块、对象存储设备的新兴存储集群架构通过将底层块的分配决策、安全增强能力分散到智能的存储设备上,并让客户端直接访问数据,简化了数据布局并消除了IO瓶颈。对象存储设备通常都是由常见的CPU、网卡、带缓存的硬盘(或RAID)等组件构成,它提供的是用来存储可命名的变长对象接口,而非传统的块存储层接口(注:也即对象存储替换了传统的硬盘或SAN设备)。

但是,采用这种架构的系统大部分都不能很好的发挥底层存储设备的潜力(注:存储节点的计算能力)。传统存储系统(本地或SAN)甚至是符合T10 OSD标准的存储节点只用来响应读写命令,并读取或写入数据到存储器,尽管存储节点有很多的计算潜力。当一个存储集群增长到上千台甚至更多设备时,数据放置的一致性管理、故障检测、故障恢复等问题会给客户端、控制节点、元数据目录节点带来巨大的负担,从而限制住了集群的可伸缩性。

我们设计实现了RADOS–一个可靠的自动化分布式对象存储系统,它旨在利用设备智能,来分散围绕在由数以千计的设备组成的存储集群周围的一致性数据访问、冗余存储、错误检测、错误恢复等的复杂性。RADOS是Ceph分布式文件系统的一部分(注:RADOS是Ceph的核心),它使一个动态的异构存储集群中不断增长的数据和工作负载二者之间的均衡变得容易,同时它能给应用提供一个单一的对象存储视角(注:节点增加、退出对应用无感),并且还能提供定义良好的安全语义(注:IO接口比较规范的意思)和强一致性保证(注:数据一致性保证,任何情况下不会读取错误脏数据,但可能无法响应IO,根据CAP理论牺牲了可用性)。

PB级的存储系统必须是动态的,系统容量是逐步扩容上去的,或者各种原因导致的缩容,也会因为旧设备的故障、退役进行设备替换,因此会有大量数据的创建和销毁。RADOS通过带版本的集群地图(注:cluster map,我这里简单的翻译成集群地图,它是用来指引各方包括client、monitor、osd等找到数据对象存放位置的)来确保数据分布和对象读写的一致性(注:可理解为通过cluster map可确定对象的分布,找到并进行读写)。cluster map被各方复制(存储系统组件、客户端等),通过惰性传播来进行小步增量更新。

通过为存储节点提供完整的数据在系统中的分布信息,设备可以半自主地使用点对点协议来自我管理数据复制,持续安全地处理更新,参与故障检测,并对设备故障和由此产生的数据分布变化做出响应,并重新复制或迁移数据对象。这简化了管理主cluster map副本的monitor集群的负担,并通过它(注:monitor?)使系统无缝地从几十扩展到上千个设备。

我们的原型实现公开了一个对象接口,使用其可以以类似文件读写的方式读取或写入字节内容,这是Ceph的最基本需求。 数据对象在多个OSD中以n个副本保存以防止节点故障。 但是,RADOS的可扩展性决不依赖于特定的对象接口或冗余策略; 存储键/值对的对象和基于奇偶校验(RAID)的冗余方案都在考虑之中(注:当前Ceph中使用RAID貌似不推荐,应该没实现)。

2. 集群伸缩管理

RADOS系统由大量的OSD和少量的monitor节点组成,monitor节点是负责管理OSD集群成员资格的(该哪些OSD加进来、踢出去等)(图1)。每个OSD通常包含CPU、内存、网卡、磁盘(或RAID),monitor则是单独的进程,只需要少量的存储空间(注:实际上还需要占用少量CPU和内存资源)。

图1
图1

2.1  Cluster Map

管理存储集群的唯一方式是通过monitor集群修改cluster map,cluster map指明了集群中包含哪些OSD,并详细记录了数据在存储设备上的分布信息,每个存储节点(OSD)以及客户端(clients)都会复制一份cluster map(注:还要保持更新)。由于cluster map完整的指明了数据分布,客户端暴露的接口就可以对调用方屏蔽集群内部包含的成千上万的存储节点的复杂性和分布式特征,使调用方可以认为在跟一个对象存储系统打交道。

每次cluster map发生变化都会导致epoch增加,map发生变化的原因可能是由于OSD状态变化(设备故障)或者其他影响数据分布的事件(注:手工修改CRUSH rule、扩容OSD等)。map的epoch可以让互相通信的各方对系统当前的数据分布达成一致,还能确定谁的信息是过期的(相对其他节点来说)。cluster map变更会比较频繁,因为大型系统中OSD故障和恢复是非常常见的,更新也是与增量map类似的分布式进行的,两次成功的epoch的差异只需要很少量的信息就可以描述。尽管通常更新中会包含许多OSD,但大多数情况下,更新简单的记录OSD错误或恢复信息,并且相距较远的两次epoch的差异会进行更新信息的打包聚合,以减少更新消息的数量。

表1
表1

2.2  Data Placement

数据存放位置。

RADOS采用了一种伪随机分配对象到存储设备的数据分布策略(注:类似hash映射,但不是完全随机的),每当添加新的存储设备时,会随机选择现有的部分数据迁移到新设备以保存均衡。这种策略是健壮(鲁棒)的,因为它保持了数据在存储设备上的概率均衡分布,通常它可以保持所有设备的负载比较接近,因而可以使得系统在任何潜在的工作负载下运行良好[22]。更重要的是,对象数据存放位置的计算是分两步进行的,不需要大量复杂的中心化位置分配表(注:不需要专门的元数据节点来管理数据存放位置,使用CRUSH算法即可解决)。

系统中存储的每个对象都首先被映射到一个PG(placement group),PG是一个逻辑上的对象集合,PG中的对象会被复制多份保存到不同的存储设备上(注:以实现副本功能,保证数据可靠性,PG是管理副本的最小单元)。每个对象所在的PG由公式pgid = (r, hash(o)&m)确定,其中o为对象名称,r为副本数量,m可以控制系统中PG总数(m = 2^k – 1),&为按位与操作,将系统中PG总数限制为2的倍数。随着系统的容量伸缩,需要定期修改m的值以调整PG总数,这个过程是逐步完成的,这样就能保证每次伸缩后需要在不同存储设备间迁移的数据量可控。

根据cluster map设置,PG会分配到OSD,每个PG对应r个排序的OSD(r为副本数量)用来实现对象的副本存储。我们利用CRUSH(一种稳定的副本分布算法)计算出一个稳定的伪随机映射(注:从PG到OSD的映射),其他数据存放策略也是可行的,即使是用明确的表来管理每个PG到OSD的映射关系,在一个相当大的集群情况下这个表也是很小的(MB级别)。从高层次抽象来看,CRUSH与hash函数的行为非常类似:PG映射关系是确定的,但是符合伪随机分布。与hash函数不同的是,CRUSH的计算结果是稳定的:即使有一个或多个设备加入或离开集群,大部分PG到OSD的映射关系是不变的,CRUSH仅移动足够的数据来维持数据分布的均衡性。作为对比,hash方法则通常需要强制重组所有之前的映射关系。CRUSH还支持设置权重来控制每个存储设备上分配的数据量,权重的设置依据可以是设备的容量或性能等方面。

注:CRUSH是另一篇论文《CRUSH: Controlled, scalable, decentralized placement of replicated data》,后面有时间会翻译。

2.3 设备状态

OSD状态

cluster map包含设备的当前状态以及设备上的数据分布的描述,描述信息包含所有在线可连通的OSD的网络地址(up状态的OSD),也包含当前离线的OSD信息。RADOS还将另外一个OSD是否存活的维度考虑在内:in状态的OSD会映射到PG,out的不会。

CRUSH会给每个PG生成一个包含r(副本数量)个OSD的列表的映射关系,RADOS之后会把down状态的OSD过滤掉,只保留活跃的OSD给PG使用。如果活跃的OSD列表为空,那么PG里面包含的数据就处于临时不可用状态,所有访问这些数据的IO操作都被阻塞(注:处于IO hang状态)。

OSD通常都处于up/in状态,可以正常提供IO服务,或者出于down/out状态,从而生成包含r个OSD的精确列表。

OSD也可能处于down/in状态,这种状态意味着OSD处于不可连通状态,但是PG里面的数据还没来得及重新映射到其他OSD(与RAID的降级模式类似)。同样的,OSD也可能处于up/out状态,意味着OSD在线但是空闲(注:未真正加入集群,没有PG分配过来)。OSD之所以有这些状态值,是为了让集群应对网络波动、OSD重启等场景时,可以不执行数据迁移操作,还可以在新存储节点上线时不必立即启用他们(比如为了提前测试网络连通性等),也可以帮助实现旧设备下线过程中安全的数据转移。

2.4 map传播

由于RADOS集群可能包含上千个OSD甚至更多,所以简单的广播cluster map的更新到各个OSD是不现实的。幸运的是,只有同一个PG内的OSD或者OSD和client之间才需要互相就cluster map的epochs达成一致,这是因为同一PG内的r个OSD需要选出一个主OSD来处理IO请求。从这方面来说RADOS可以利用OSD之间通信的机制来进行cluster map的惰性更新,从而将cluster map更新相关的负载下放到各个OSD上。

每个OSD都维护一份cluster map增量更新的历史记录,所有消息都带有最新的epoch标记,当OSD与其他OSD通信时都会对最近的epoch进行跟踪。如果一个OSD接收到另外的OSD消息时发现其map的epoch版本比较老,则当前OSD会把增量更新分享给它以便让他同步到新版map。类似地,当主动发消息给其他OSD时,如果发现对端map的epoch版本比较老,也会触发cluster map的增量更新流程(注:不管是主动还是被动通信,如果发现对端版本较老都会同步cluster map)。同时,用于错误检测(见3.3节)的OSD定时心跳消息也会携带map信息,以确保map更新以O(log n)的收敛速度快速扩散到整个集群的n个OSD。

举例来说,当一个OSD第一次启动时,它会发送一个OSD启动的通知给一个monitor(见第4节)表示它上线了,这个启动消息包含了OSD本地最新的map epoch版本号。之后monitor集群会把这个OSD置为up状态,并把cluster map的增量更新信息发送给OSD,以便确保它获取的是最新的版本。当这个新的OSD开始与和他共享数据的OSD建立联系时(见3.4.1节,注:新的OSD分配了PG,其他OSD是一起保存对象的多个副本),受这个新OSD的状态变更影响的精确OSD集合会学习到恰当的cluster map更新(注:同一个PG的多个OSD副本之间互相建立关系时保持一致的map版本)。由于OSD启动时不清楚对端的OSD保存的map epoch,所以它会分享至少最近30秒的增量更新历史版本给对端。

这种抢占式的map共享策略是保守的:一个OSD会一直跟对端(注:对端表示同一个PG的多个副本所在的OSD)共享map更新,除非它确信对端已经获取到这个更新,这就导致OSD会接收到重复的map更新信息(注:相同的map更新信息一个OSD收到多次)。但是,一个OSD接收到的重复信息的数量会受到对端数量的限制(注:也即副本数量),因此也受限于一个OSD上包含的PG数量(注:副本数量一定的情况下,一个OSD上PG数量越多,接收到的重复消息越多)。在具体实践中我们发现OSD真正接收的重复更新消息数量是比上述理论值要少很多的(见5.1节)。

3. INTELLIGENT STORAGE DEVICES

智能存储设备(注:意思赋予了OSD计算能力,可以用来处理数据副本、错误检测、错误恢复)

cluster map包含的数据分布信息可以让RADOS将数据冗余备份、错误检测、错误恢复等方面的能力分散到组成存储集群的各个OSD上。在一个高性能的集群环境中,通过点对点类似的协议可以很好的利用OSD的计算能力。

RADOS当前为每个PG实现了n路复制(注:多副本功能)、对象版本和短期日志(注:应该是指journal功能)功能。复制是有OSD自身负责执行的:客户端提交一个单独的写操作到主OSD,之后主OSD会负责一致、安全地更新到所有副本(注:同一个PG内的其他OSD)。这个设计将副本相关的带宽转移到了存储集群内部网络,并且简化了客户端的设计(注:不需要考虑副本问题)。对象版本和短期日志功能则使存储节点间歇性故障场景(如网络断开或节点宕机/重启)下的恢复变得更快。

我们在这一大节内容中会主要描述RADOS的架构,特别是cluster map相关的架构,因为它是实现分布式副本和恢复操作,以及这些能力可以适用于其他副本机制(如基于奇偶校验的RAID)的关键。

3.1 副本

RADOS实现了3种副本方案:primarycopy [3],chain [26],以及一个我们称之为splay的混合方案。图2展示了一次更新操作(注:写IO)的消息交换流程,在所有方案场景下,客户端发送IO操作到一个OSD(每次IO操作对应的OSD可能是不同的),存储集群会确保副本被安全的更新并且读写语义的一致性(如经过序列化)会被保留。当所有副本都被更新之后,会返回一个通知消息给客户端。

图2
图2

Primary-copy副本方案会并行更新所有副本,并且读和写请求都在主OSD上处理。Chain副本方案则是顺序更新所有副本:写操作发送到主OSD处理,读操作则在最后的副本上进行(注:更新顺序是从主到从,从头到尾),以此来确保读操作总是获取完整更新过的副本内容(注:所有副本都更新过了才放行读操作)。splay副本方案则简单的把primary-copy方案的并行更新机制以及chain方案的读写角色分离结合在一起,其主要优点是2路镜像场景(注:应该是说2副本情况)下的消息交换数量比较少。

3.2 Strong Consistency

强一致性

包括client以及其他OSD生成的所有的RADOS消息都会被加上map的epoch标记,以此来确保所有更新操作都能被完整一致的实施(注:这句话没太理解,感觉应该是说有了版本号才知道最新的数据分布,不会导致数据更新不一致)。如果一个客户端由于其拥有的map是过时的而发送了一个IO请求到错误的OSD上,OSD会把map的增量更新返回给客户端,之后客户端就可以重新发送请求到正确的OSD。这就避免了主动推送cluster map更新到客户端的需求,因为客户端可以在与存储集群交互过程中获取到map的更新。大部分情况下客户端都可以在不影响当前IO操作的同时把之后的IO重定向到正确的OSD。

如果cluster map的主副本已经更新并影响到一个PG的成员关系,PG的成员还没有得知map的更新,对象更新可能被PG的旧成员处理。如果map的变更首先被PG中的某个非主副本得知,则当主副本所在的OSD转发更新IO操作到次副本或其他副本时,次副本会把新的map更新返回给主副本。这个流程是安全的,因为map更新后PG对应的新OSD集合需要首先与PG之前对应的旧OSD集合建立联系,以便确定PG正确的数据内容,这就确保了之前的OSD可以得知map更新,并停止执行IO操作直到新的OSD启动。

让读操作达到与更新操作类似的一致性会更加复杂,在类似网络断开导致一个OSD只能被部分节点连通的场景下,这个OSD不应该为可以连通它的使用旧的map的客户端提供PG读操作。同时,更新后的cluster map会指定一个新的OSD来替换这个异常的OSD,为了在更新操作被新OSD接管后阻止任何读操作被旧的OSD处理,我们需要在PG的OSD之间保持周期性的心跳消息,以便确认OSD是否存活从而保证PG是可读的,具体策略是,当一个提供读操作的OSD超过H秒都没有收到PG内其他副本的心跳消息,则它会暂停提供读操作(注:因为写操作需要从主OSD转发到各个从OSD,已经保证了各个OSD都要在线才能执行,而读操作则不然,可以在PG的任何OSD上执行,因此需要叠加OSD心跳机制来保证PG的读操作可执行)。在一个OSD接管PG的主OSD角色之前,它必须要么获取到旧OSD主动发送的确认消息(确保旧OSD知道他们的角色变化),要么继续等待H秒。在当前的实现中,我们设置了一个比较短的心跳间隔(2秒),这保证了错误检测周期很短,也保证了PG的主OSD异常时PG里数据不可访问的持续时间较短。

3.3 Failure Detection

错误检测

RADOS实现了一个异步的、顺序的点对点消息传递库用来传递消息,TCP错误导致的消息传递失败会进行有限次数的重连尝试,重试无效会将错误信息上报到monitor集群(注:消息传递的一端网络异常、节点异常等场景会进行消息重发)。同一个PG内的存储节点(OSD)之间周期性的交换心跳消息以确保OSD异常可以被检测到,当OSD发现它被标记为down状态之后,会在执行数据落盘操作之后自杀,以确保数据一致性。

3.4 Data Migration and Failure Recovery

数据迁移和错误恢复

RADOS数据迁移和错误恢复是完全由cluster map的更新以及由此引发的PG到OSD映射变化驱动的,这种变化可能是由于设备(注:此处设备指代OSD)故障、恢复、集群扩缩容,甚至是由于CRUSH副本分布策略更新导致的整体数据重新分布引发,有众多可能原因会导致存储集群建立新的数据分布,设备错误是其中最简单的一个。

RADOS不对两个map之间的数据分布做任何连续性假设(注:map更新前后可能导致数据分布变更),在所有情况下,RADOS采用健壮的对等算法来建立PG数据一致性视图,也是用该算法来恢复数据的恰当分布和副本。这种策略依赖一个基本的设计前提:即使本地对象副本丢失,OSD可以主动复制PG的日志,这个日志记录了PG的当前应该保存的内容(例如保存的对象版本为何)。因此即使恢复比较慢、对象的安全性在一段时间内降级,PG的元数据是会小心保管的,这就简化了恢复算法,并且使得系统可以可靠地检测出数据丢失。

3.4.1 Peering

结对(注:同属一个PG的各OSD之间进行结对)

当一个OSD接收到cluster map的更新后,它从远及近地遍历所有新的增量更新,检查并可能会调整PG状态值,所有本地保存的PG的在线OSD列表发生变化后都会被标记为需要重新结对。顾及到所有map epoch而不是最近一个是为了确保所有中间数据分布的变化也被考虑在内:如一个OSD被从PG中移除后又再次加入该PG,了解PG内容中间更新过程可能已经发生是很重要的(注:这部分没太理解,应该是说cluster map多次更新可能导致数据分布发生了变化,但cluster map最终并没有发生变化,所以为了保证数据一致性,需要确保每次map的更新都被正确处理)。类似副本过程,结对过程以及随后的数据恢复过程也是在每个PG中各自处理的。

结对过程是由PG的主OSD发起的,对于OSD保存的每个PG来说(注:一个OSD上有多个PG,OSD在一个PG里可能是一个副本OSD,也可能是一个已经离线的OSD),如果OSD不是PG的主OSD,那么它就会发送一个通知消息给PG当前的主OSD,消息内容包括OSD本地保存的PG的基本状态信息,最新的map更新,PG log的边界,以及PG成功结对后最近获知的epoch。通知消息确保PG里一个新的主OSD可以发现它的新角色,而不必为每次map变化考虑所有可能的PG(可能是数百万个)(注:这段应该是说map变化只影响涉及到的PG,而与其他PG无关)。一旦意识到角色变化,主OSD会生成一个优先集合,集合包含了参与PG的所有已成功结对的OSD,通过显式查询优先集合之后会给集合中的每个OSD请求一次通知消息,以避免无限等待一个实际没保存这个PG的OSD(例如对于中间状态的PG映射结对永远无法完成)(注:这部分没太看懂,是说主OSD会主动发消息给PG内其他OSD并让他们回复,以便完成结对?结对过程是要两方都确认才算真正结对成功?)。

有了整个优先OSD集合的PG元数据,主OSD可以确定已应用到每个副本的最近更新,并且向优先OSD请求任何PG日志的片段以便使得所有在线副本OSD的PG日志同步到最新。如果可用的PG日志不足(例如一个或多个OSD没有任何PG的数据),则会生成一个完整PG内容的列表(注:这句没看明白,生成这个列表有啥用?是说数据不完整的也会记录起来?之后怎么处理呢?)。但是对于节点重启或者其他短时间的中断情况来说,这个流程是不需要的,最近的PG日志就足以快速地重新同步所有副本。

最后,主OSD会将丢失的日志片段共享给副本OSD,之后所有副本就都知道了PG应该包含的对象(即使这些对象可能在OSD上不存在),并且在后台进行数据恢复的同时开始处理IO请求。

3.4.2 Recovery

分组副本(declustered replication)一个关键优势是可以进行并行故障恢复,一个故障OSD的相关副本是分散到多个其他OSD的,故障OSD加入的每个PG会独立的选择一个替代品,让副本重新复制到替代OSD。一般来说,在一个大型系统中,介入一次故障恢复过程的OSD只会在一个PG上获取或推送数据内容,这使得恢复过程非常快速。(注:这段是说一个OSD挂了,则PG会找一个新的OSD替代它,这个OSD会把挂了的OSD的数据副本同步过来,同步过程是从挂了的OSD加入的所有PG包含的其他OSD上获取数据,而其他OSD则是推送数据给替代OSD,因此每个介入恢复过程的OSD–非替代OSD–都只负责一个PG的数据恢复,大型系统的PG比较分散,参与恢复过程的两个OSD包含同一PG的概率比较低)

RADOS的故障恢复是在观察到IO操作经常性被读吞吐量限制后激发的(注:上面讲过,OSD心跳超时后读操作会被block,但为啥不是观察写入被限制呢?)。尽管每个独立的OSD配合PG元数据都可以单独的获取丢失的对象,这个策略仍然有两个局限性,首先是同一PG的多个OSD独立恢复对象过程中,它们不一定会同时在同一批OSD拉取同样的对象,这就引出了恢复过程代价最大的问题:寻址和读数据;其次是当副本OSD丢失了被修改的对象时,副本更新协议(见3.1节)就变的更加复杂(注:IO写入过程要在每个副本OSD完成后才返回给客户端,如果一个副本OSD没有这个写IO操作的对象,则需要进行特殊处理才行,比如要先把副本同步过来才能继续执行写操作,本次写IO返回执行失败结果给客户端?)。

基于上述原因,RADOS的PG数据恢复是由主OSD协调的,如前所述,操作主OSD丢失的对象时会被阻塞直到主OSD同步对象数据到本地,由于主OSD通过结对过程已经知道所有副本OSD丢失的对象信息,所以它就可以主动推送丢失任何即将被修改对象到副本OSD,这就简化了副本同步逻辑,同时也保证了存活的副本只需要被读取一次(注:被主OSD读取一次之后主动推送到副本OSD)。在主OSD推送对象(注:客户端通过主OSD获取对象)或者为自己拉取对象过程中,它会在对象还在内存中时将对象推送给所有需要这个对象的副本OSD,因而总体上每个被恢复副本的对象仅会被读取一次。

4. MONITORS

一个小的monitor集群通过保存cluster map的主副本,并定期更新以响应配置更改或OSD状态更改(例如,设备故障或恢复),来共同负责管理存储系统。该集群部分基于Paxos part-time parliament[14],旨在支持一致性和持久性,而不是可用性和更新延迟。 值得注意的是,必须在多数monitor可用时才能读取或更新cluster map,并保证做出的更改的持久性。

4.1 Paxos Service

monitor集群是基于Paxos算法实现的分布式状态机服务,其中cluster map是当前机器状态,map每次成功更新都会产生新的epoch。我们的实现通过一次只允许一个并发map变更来简化标准Paxos(与[17]类似),同时将基本算法与租约机制相结合,允许将IO请求发给任何monitor节点并且仍能确保IO读取和更新操作的一致性。(这个功能已经被实现为通用服务,它还被用来管理Ceph的全局数据结构,其中包括用来协调客户端访问存储系统的MDS的cluster map和状态)

monitor集群会初始选举出一个leader并由它来负责序列化cluster map的更新和管理一致性。leader一旦被选举出来就会向每个monitor节点请求map的epoch,monitor节点需要在固定时间T内(目前T为2秒)做出回应并加入选举的法定人数。如果存活的monitor占多数,Paxos算法的第一阶段保证每个monitor拥有最近提交的cluster map epoch(可以向其他monitor按需请求cluster map的增量更新),之后开始给每个monitor发布短期租约(注:意思是每个monitor都是最新的map了,就可以开始对外服务了,但是为了保证map的时效性、对象数据的一致性,需要增加租约有效期限制,租约过期了就需要重新获取map和续租)。

在每个租约有效期内的存活monitor被允许分发cluster map的副本给请求cluster map的OSDs或者客户端,如果超出租约有效时间T都没完成续约,则认为leader monitor已经死亡,然后发起新的选举。每个monitor的租约都需要通过发送收据通知给leader monitor来确认,如果一个租约发布后leader没有及时接收到某个monitor节点的确认消息,leader节点会假设这个monitor节点已经死亡,并发起一次新的选举(建立新的选举法定人数)。当一个monitor第一次启动时,或者发现之前发起的选举在合理时间段内没有结束,就会发起新的选举。

当一个正常的monitor节点接收到一个更新请求(如有错误发生)(注:更新请求是指请求获取map更新),它会先检查这个请求是不是新的,举例,如果发送更新请求的OSD已经被标记为down,那么monitor会简单的恢复必要的增量map更新给OSD让它保存的map保持最新版本,而如果是有新的错误发生则会转发给leader monitor节点,由它负责聚合多次更新。leader monitor会通过增加map epoch来定期发起map更新,并利用Paxos更新协议将更新提案分发给其他monitor节点,与此同时还会撤销之前的租约。如果更新被多数monitor节点确认,leader节点最终提交map信息并生成一个新的租约(注:Paxos协议的第二个阶段)。

同步两阶段提交和探测间隔T的组合使用可以确保如果monitor的存活集合发生变化,所有之前的租约(还在有效期T内)都会在任何后续的map更新发生之前过期。因而,只要多数monitor节点可用,任何顺序的map查询和更新会导致map版本的一致性前进(持续增加版本号),无论消息发给哪个monitor、不管monitor发生什么故障,版本号都不会倒退。

4.2 Workload and Scalability

工作负载和可扩展性

一般情况下,monitor做的事情非常少:大部分map分发都是OSD节点处理的(见2.4节,注:通过PG的OSD结对机制来搞定),而OSD状态变化(如由于设备故障)通常都不频繁。

monitor集群内部使用的租约机制可以允许任何monitor节点处理来自OSD的读IO请求或者来自客户端的获取最新的cluster map请求,这些请求很少由OSD发起,因为它们有主动map共享机制,而客户端请求map更新仅会在检测到OSD发生操作超时错误时才会执行,对于大型存储集群,可以通过扩容monitor集群来分散它们的工作负载。

获取新map的请求(如OSD启动通知或首次上报故障)会被转发到leader monitor,leader会聚合多次map变更到一个map更新,因此map更新的频率是可调的,并且与存储集群的大小无关。尽管如此,最严重的负载会发生在短时间内大量OSD出错场景下,如果每个OSD上面有µ个PG,同时有f个OSD出错,则在一个大型OSD集群经历一次部分网络中断故障时,最多会有µ*f个错误报告会产生(注:每个OSD上的PG都完全不同的场景),这个数字可能非常庞大。为了防止这种消息泛滥问题,OSD在半随机间隔内发送心跳用来将检测到OSD故障的时间错开,之后对错误上报消息进行限流和批量化处理,这样就可以让monitor集群的负载与存储集群大小成比例关系。非leader monitor节点之后仅转发一次错误报告消息(注:转发前会检查是否已经转发过,只转发那些没转过的消息),因此leader节点的负载与f*m成比例关系(m为monitor节点数量)。

5. PARTIAL EVALUATION

这是一个专有名词,不知道怎么翻译,参考资料:

利用起来每个OSD的对象存储层的性能在Ceph那篇文章[27]中已经被测量过,类似地,CRUSH的数据分配性能以及他们对集群吞吐量的影响也被评估过[27,28]。在本篇文章中我们仅聚焦在map分发性能方面,因为这个问题对集群伸缩能力有直接影响,尽管我们在架构上对系统的可扩展性有信心,但我们还没有通过实验评估monitor集群的性能表现。

5.1 Map Propagation

RADOS map分发算法(见2.4节)确保map的更新可以在logn跳内到达所有OSD,然而随着存储集群扩容,设备故障以及与此相关的集群更新的频率也会增加,由于map更新仅在同一PG内的OSD之间交换,一个OSD能接受到的同一个map更新的次数上限与µ成比例关系(µ是OSD上PG数量)。

在定期进行map更新情况下的接近最差map传播环境的模拟场景下,我们发现即使在指数级集群扩容场景下map重复更新(注:传播的更新数与实际更新数的比值)也是接近稳态的,在模拟实验中,monitor会分享map到一个随机的OSD,之后OSD会把map分享给PG里的其它OSD。图3展示了我们通过调整集群大小x以及每个OSD上的PG数量(对应每个OSD有几个对端),得出的一个OSD接收的重复map更新消息数量y。map更新的重复消息量接近一个常量,少于µ的20%,即使集群大小成指数级扩展,也只会产生固定的map分发开销。我们还考虑了一种最差场景,让一个OSD频繁的上下线,导致其获取map更新非常慢(更新已经被它的对端获取),这种情况下map分发的开销只依赖于map更新频率限流情况,而这种限流monitor集群已经做了。

图3

图3

6. FUTURE WORK

我们当前已经实现了一个工作良好的对象存储系统,这个系统是Ceph分布式文件系统的基础,但这个对象存储系统提供的可伸缩集群管理服务不仅能满足Ceph的需求,而且还更加通用,我们还有很多额外的方向需要进一步研究。

注:第6节内容与RADOS关系不太大,就简单的翻译下。作者提到了一些考虑到的后续研究方向,实际上应该很多都没做,这也是写论文的常见套路,主要是为了说明论文内容的普适性和可持续性。

6.1 Key-value Storage

这里应该是说RADOS当前只用来存储对象,实际上它还可以用来保存key-value键值对,实现类似mongodb、memcache、redis等NoSQL数据库的功能。

6.2 Scalable FIFO Queues

基于RADOS实现一个可伸缩的先进先出队列服务。

6.3 Object-granularity Snapshot

对象粒度的快照功能。这个需求是Ceph需要的。

6.4 Load Balancing

热点对象的负载均衡,场景是大量客户端同时访问同一个对象,会导致这个保存这个对象的OSD节点负载很高。这确实是一个值得研究的方向,问题很有现实意义。

6.5 Quality of Service

QoS,保证故障恢复期间客户端的IO操作性能不受大的影响或者受影响的程度可控制,这也是一个值得研究的方向,也是Ceph社区当前的重点改进方向。

6.6 Parity-based Redundancy

基于奇偶校验的冗余,我理解应该是研究除了副本冗余策略之外的其他策略,Ceph当前已经实现了EC纠删码冗余策略

第7节是相关工作,第8节是小结,都是科研论文的一般讨论,就不再翻译了。另外还有最后的参考文献也不列出来了,有需要可以参考论文原文。

后面有时间我会把剩下的两篇论文也翻译下:

  • CRUSH: Controlled, scalable, decentralized placement of replicated data
  • Ceph: A scalable, high-performance distributed file system(2018-04-24更新:这篇看了下,只讲了MDS相关的,感兴趣的rbd相关的没看到,就不翻译了)

VisionStack-3.2.0版本研发历程

版本历史回顾

罗马不是一天建成的,VisionStack-3.2.0版本也不是一触而就的,在此之前还经历了2.1.x~3.0.x~3.1.0这几个版本的迭代过程,为啥要写3.2.0版本的研发历程呢?我以为是这个版本真正接近完善,精心打磨出来的一个简单易用、稳定可靠的私有云产品。因此接下来描述的新功能、重构等也包含了前几个版本的开发内容,也不做一一区分说明了。

一个好汉三个帮,VisionStack-3.2.0的完成是云容研发、产品、交互视觉团队及客户共同努力的成果。

VisionStack第一个版本的控制台是通过对原生horizon进行简单的面板修改产生的,属于实验性质,就不再详细描述,我们先看下最早2.x的产品界面:

 

再看下3.1.0版本之前的产品控制台界面:

前两个大版本控制台存在的问题:

  1. UI美观度不高
  2. 人机交互体验不够好
  3. 操作流畅度较差
  4. 排版布局比较乱
  5. 切换页面有空白过渡页
  6. 关键操作、功能限制等提示信息匮乏

最后看下3.2.0的产品界面:

可以看出每个版本界面在美观度方面我们都有很大的进步,但更多的改进是在用户体验方面(页面排版布局、操作流畅度、页面卡顿情况、人机交互流程等),可以说3.2.0版本有了质的提升。查询类操作在3.2.0之前都超过秒级,而3.2.0则绝大部分都在500ms以内,另外之前的版本一旦点击导航菜单切换页面,就会全面刷新整个浏览器页面,有很长的空白过渡页,新版本采用fullpage方案,除非手工按刷新按钮否则全部采用局部刷新,再也没有难看的空白过渡页,此外还新增了大量提示信息,支持全部页面的导出excel功能,大部分列表项目的模糊搜索功能,以及列表页自定义展示信息条数等用户友好功能。

技术演进过程

产品界面只是研发内容的冰山一角,更多的内功是在后台服务的重构更新方面,简单列一下近一年来我们重构或新增的功能(未区分时间先后):

  • 云主机:
    • 前端去掉了不符合用户习惯的卡片式列表模式
    • 列表项增加了挂载云硬盘图标、虚拟IP、限速信息展示
    • 重构在线扩容功能,支持扩容超过8核16G规格
    • 支持cloud-init/cloudbase-init执行云主机初始化
    • 新增支持win10、win server 2016版本镜像,Centos、Ubuntu等多个Linux发行版的多个版本镜像
    • 重构备份功能,并支持了在线备份,磁盘限速、网络限速功能
    • 新增重装系统功能,软重启功能,在线快照,创建过程支持设置密码(win系统)、设置安全组、配置公有私有2个网络、防误操作、可创建台数提示等
    • 重构云主机详情页,增加安全组、负载均衡、虚拟IP、伸缩组等信息
  • 容量计算
  • 防误操作
  • 监控系统
    • 进行了大的后端重构
    • 支持了磁盘使用量、使用率、IOPS、BPS监控
    • 支持了云硬盘的监控
    • 增强了对Windows系统的监控支持
  • 计费系统
    • 重构整个计费服务(移除对nova代码侵入改动,支持账单周期、审计功能等)
    • 支持云硬盘计费
    • 支持租户费用概览、详单功能
  • 项目和用户管理
    • 增加角色,支持4种等级:超级管理员、系统管理员、项目管理员、普通用户
    • 权限功能重构,配合角色等级可精细化控制每个页面每个按钮是否可用
    • 支持了用户组功能
    • 配额增强,新增支持系统盘(后台实现方案重构)、云硬盘容量及数量(按类型)、云硬盘快照数量(按类型)、伸缩组数量、安全组数量、安全组规则数量的配额管理
  • 镜像管理
    • 支持了镜像的禁用启用
    • 支持了操作系统和发行版版本设置
    • 支持了上传镜像进度条展示
    • 支持了镜像实际大小和虚拟大小(防止用自定义镜像创建云主机时选择小于镜像虚拟大小的系统盘规格导致创建失败)
    • 限制使用Ceph存储后端时只能上传raw格式镜像
  • 物理机和可用域管理
    • 可用域更名逻辑增强
    • 默认可用域显示逻辑增强(没有物理机在默认可用域时不显示,并且不能把其他可用域的物理机移动到默认可用域)
    • 物理机在可用域之间移动逻辑增强
    • 可用域和项目绑定逻辑增强(多对多映射关系)
  • 云硬盘
    • 支持云硬盘功能(适配Ceph、LVM、SAN后端)
    • 支持多种云硬盘类型(容量型、性能型、混合型)
    • 支持后端容量不足提示
    • 支持只读、读写模式
    • 支持云硬盘快照
    • xsky的ceph支持multiattach,官方开源版本不支持,所以我们没做multiattach
  • 云网络
    • 虚拟IP(port-update –allowed-address-pair)
    • 安全组:基于openvswitch原生安全组功能实现,未使用Linux bridge+iptables方案
    • 简化了网络管理的操作流程
  • 概览页
    • 完全重构,平台管理员概览页增加了平台资源总览、项目云主机用量概览、平台资源使用量、回收站资源信息、近期告警信息等内容
  • 移动客户端
    • Android版本已经开发完毕,IOS版本正在开发(重构版本采用跨平台方案)
    • 支持告警信息推送、资源使用量概览、监控图表查看等
  • 云主机弹性伸缩
    • 基于OpenStack senlin项目开发而来,并进行了定制化增强
    • 支持告警伸缩、定时伸缩功能
    • 具有伸缩组、伸缩规则、伸缩配置管理功能
    • 伸缩动作触发后通知用户功能正在开发中
  • 云负载均衡
    • 基于neutron-lbaas-agent开发,支持TCP、HTTP、HTTPS三种协议
    • 支持负载均衡后端的健康检查功能
    • 高可用功能正在调研中
  • 操作日志及平台日志
    • 补全了绝大部分操作的日志记录,如用户登录、修改权限、云主机创建、安全组创建、网络创建、各种资源的删除修改等
    • 平台日志重构,去掉了用户不关心的平台错误日志记录,改为在平台巡检中提示用户平台服务产生的错误日志条数
  • 设置页
    • 支持云主机资源(cpu、内存、系统盘)、云硬盘资源(按类型的容量)的复用比例设置功能
    • 支持自定义logo功能,可替换包括favicon在内的VisionStack控制台内所有logo相关资源
  • 平台巡检
    • 重构整个后端服务,实现功能高可用
    • 支持所有平台服务的状态、进程存活、端口连通性、物理机连通性等方面的巡检
    • 支持立即巡检、定期巡检功能,定期巡检支持按小时、天、周设置周期,并且巡检结果可通知到用户
  • 告警系统
    • 重构整个后端服务,实现功能高可用
    • 支持云主机、物理机的各个监控维度的阈值告警,细粒度支持单个cpu核级别的阈值告警
    • 支持通道沉默时间、连续告警次数设置功能
    • 支持短信、邮件告警,支持控制台告警提示
  • 平台运行报表
    • 整体平台资源情况概览
    • 资源使用量TopN用户/项目
    • 物理机、云主机利用率TopN节点
    • 平台/项目告警次数概览
    • 租户操作次数概览
    • 定期邮件发送报表
    • 功能增加中,预计增加更多平台使用优化建议类信息
  • 管理员全局视图模式
    • 全局模式不区分项目,可统一查看所有项目的资源
    • 全局模式不可执行创建、删除、修改等操作,属于只读模式
  • 激活码功能
    • 支持序列号、激活码功能
    • 支持控制节点数量、有效期等属性
  • 多区域
    • 支持了多区域(Region)功能,一个控制台管理多个机房
  • 业务监控
    • 支持HTTP/S、FTP、TCP、UDP、DNS、PING、SMTP、POP3等协议的监控
    • HTTP/S支持GET、HEAD、POST请求,告警规则支持错误码和响应时间监控
    • DNS支持A、NS、CNAME请求
    • 其他告警规则支持响应时间监控
  • 通知对象
    • 支持管理通知联系人,可添加手机号、邮箱并支持验证码
    • 全局共用通知对象,可在所有需要通知用户的页面选择通知对象

后台服务重构及新增情况:

  • friedrice
    • 类似计算节点外挂服务,对外提供HTTP RestFul API,可用来设置云主机的磁盘、网络限速(QoS),以及获取各种文件信息
  • hearkener
    • 消息队列监听服务,收集到资源操作通知后做出对应的操作,如记录操作日志,调用回调服务等
  • sqlants
    • 数据库中间件服务,对外提供HTTP RestFul API,用来操作vscloud关系数据库(VisionStack新增数据库),为所有自研项目提供数据库交互操作接口
    • 对外接口支持基于用户token的认证
  • turtle
    • 定时任务服务框架,基于apscheduler开发,集合了云主机物理机阈值告警、云主机告警伸缩、云主机定时伸缩、各种信息如后端存储空间等的定期上报、平台巡检、云主机定时备份、平台周期报表、业务监控、云主机物理机监控数据上报
    • 通过数据库表管理定时任务,使用数据库记录与前端进行任务交互
  • qemu-guest-agent
    • 进行了较多的二次开发,加入了多个维度的云主机监控数据获取接口,配合监控数据上报实现秒级实时监控和分钟级监控数据上报
    • Windows和Linux都有涉及
部署架构图

后端服务已经做到全部高可用化部署(nova-compute等不支持高可用的服务除外)。

前端技术演进

原生horizon的体验较差,尤其是查询类操作响应时间比较长,因此我们2.X版本使用了数据库触发器同步OpenStack原始数据库信息到vscloud相关表,并通过中间件进行信息的查询和聚合,改造了horizon的查询接口(从调用OpenStack各服务的API改为调用查询中间件服务API),极大的减少了页面列表的响应时间,但该版本仍然是Django框架,所有页面都有后台horizon渲染后返回给浏览器,还有部分css、js、html的逻辑不合理,代码复用比低等问题,另外一些问题也在文章前面章节有所表述。

在3.X版本我们采用了流行的fullpage模式,配合前后端分离框架,做到了所有页面的框架代码一次性加载完毕,子页面跳转不需要经过整个页面的加载过程,大大提高了用户体验,同时我们还做了一次整体的UI改版,很好的提升了控制台的美观度。

3.X版本我们使用的前端工具链vue.js+elementUI+webpack,打包后放到Apache服务器上。

如何保证平滑演进?

从2.X到3.X版本前端改动虽然很大,但只要正常升级即可,对用户已经使用的功能不受影响。但后端服务在演进过程中就要考虑平滑过渡问题,不能导致升级后以前的功能或者数据受到影响。

后端服务重构,主要是把之前一下crontab的定时任务脚本改造成定时任务服务的一部分,另外去掉了监控服务对collectd的依赖,把所有服务都采用rpm包进行管理维护,以便于部署更新。相关的数据库表在重构服务过程中,要优先考虑数据迁移问题,保证老数据不丢失。

研发流程与项目管理

研发流程采用敏捷迭代开发,每个迭代周期在2周到1个月左右,一个完整的迭代包括需求确认、需求分析、功能模块设计、代码开发、代码review(所有代码必须经过review方可merge)、开发环境更新、测试、版本发布、集成测试这几个阶段。

版本分为内部版本和外部版本,一般通过版本是否存在影响用户使用的功能缺失或严重bug来进行区分。

代码使用分支或tag来标记版本。内部版本使用tag,外部版本使用branch,一般新版本发现或修复的严重bug要backport到比较临近的几个外部版本的分支上,正常情况下都是通过给用户更新到最新的外部版本来解决新发现的bug。

项目管理采用站会+周例会模式,并经常不定期的举行头脑风暴,进行需求的分析、原型的讨论、UI的确认、功能模块方案的交流等。所有的功能实现方案、UI等都需要有文档记录。

团队能力提升

  • 疑难问题处理能力:不定期进行问题定位分享会,交流问题定位心得和工具等
  • 方案设计能力:所有需求分析、实现方案都有文档放到wiki服务器(并经过review),供所有研发同事查看
  • 工作氛围改变:解决问题的信心、功能设计的实力、能力提升的成就感等大大改善了工作氛围
  • 开源社区贡献
  • 团队组建及人才梯队培养:保证一个方向至少有2个开发人员比较熟悉,并尽量交叉分配到各个项目或功能模块,增强模块设计的全局观
  • 新员工学习计划:为每个新入职员工定制学习计划,指定导师,方便快速上手

运维及交付流程

  • deploy_tools:安装部署工具,实现一键安装部署,支持指定版本号和节点类型
  • upgrade_tools:版本升级工具,实现一键升级,支持指定节点类型,支持指定原版本号和目标版本号,可自动更新两个版本间的数据库表结构变动

测试自动化

  • 半自动化测试环境更新:目前是一键执行更新脚本即可完成测试环境的更新,可稍作改进后做到定期自动化更新
  • yr_automated_testing:基于selenium的web自动化测试工具,正在逐步完善,用excel保存测试用例名称、元素类型、位置、执行的操作、等待时间、结果校验值等,代码量极少,可每天自动进行web测试,并将测试结果邮件通知到研发测试人员
  • 使用tempest进行后端API接口测试

后续目标

  • 计算节点安装部署web化
  • 用户业务部署自动化(DevOps)
  • SDN(overlay网络)
  • 负载均衡高可用
  • 云主机高可用
  • 持续集成(静态代码检查、集成测试等)
  • 项目管理能力提升
  • 研发人员技能提升
  • 开源社区贡献
  • ……

 

SonarQube静态代码检查工具环境搭建

参考文档:

安装环境:centos7.4 64bit

安装过程

    1. 安装jdk8:yum -y install java-1.8.0-openjdk java-1.8.0-openjdk-devel(devel包应该可以不装)
    2. java -version查看版本及确认是否正常安装
    3. yum install postgresql-server,安装postgresql
    4. systemctl enable postgresql,systemctl start postgresql
    5. sudo -s -u postgres,创建数据库账户和库:

      修改postgresql认证配置(tcp连接改用password认证方式):

      最后重启服务:systemctl restart postgresql
    6. 下载sonarqube-6.7.2(首先LTS版本):https://www.sonarqube.org/downloads/
    7. unzip sonarqube-6.7.2.zip(官方提示不要解压缩到绝对路径里包含以数字开头的文件夹里面,比如/data/123/abc这种)
    8. 之后修改sonarqube配置,配置文件在sonarqube-6.7.2/conf/sonar.properties:
    9. useradd sonar:创建sonar用户,sonarqube不能用root用户启动(elasticsearch要求非root用户启动,而sonarqube又默认启用这个elasticsearch插件)
    10. chown sonar.sonar -R sonarqube-6.7.2:修改目录所属用户,防止无法写入日志导致启动失败等问题
    11. su sonar,进入sonar用户进行操作
    12. cd sonarqube-6.7.2/bin/
    13. ./sonar.sh start启动
    14. 打开浏览器输入:http://IP:8080/sonar(根据上面的sonar.web.port=8080、sonar.web.context=/sonar确定端口号和URL后缀),默认用户名密码是admin、admin
    15. 之后根据官方文档进行python代码静态检查环境的下一步配置即可

 

neutron vlan+ovs组网模式下的云主机网络数据流分析

本篇是上次的neutron配置项分析的一个延续,也是近几年的一个长期未了的心愿,之前看过OpenStack官方的networking guide,学习了一下理论上的数据流,但毕竟纸上得来终觉浅,必须要亲自调试、观察、验证一下才能真正有深入的理解,这篇文章就是为了这个目的来写的。

这是第一次分析neutron云主机网络数据流,因此挑选比较简单的vlan+ovs+物理网络设备方案,省的把自己搞晕,然后后面如有时间,再继续分析vxlan+ovs+overlay网络+物理网络方案。

环境

OpenStack mitaka(nova+neutron+glance+keystone)

neutron:server、openvswitch-agent、dhcp-agent(未使用l3-agent、metadata-agent),l2 mechanism_drivers配置的是openvswitch,2.6.1版本(未使用Linux bridge),安全组也基于openvswitch原生功能(已经在云主机上配置上下行全通安全组策略),type_drivers = vlan、tenant_network_types = vlan,物理网络都是VLAN模式,各个VLAN之间在物理交换机上配置了3层路由策略实现互通。

物理网络环境:办公区使用的是电信家庭宽带,无固定公网IP,无法做NAT,通过光猫拨号上网,服务器连接的物理交换机上联到光猫。物理服务器上的网卡em1、p5p2分别对应管理网和业务网,网桥br-int、br-p5p2通过patch port连接。

使用工具

tcpdump、ping

分析场景

同租户下同一台宿主机上的两台云主机(同网段、同VLAN、同物理机)

两台云主机ip分别为10.0.70.215、10.0.70.216。

这种场景非常简单,数据包直接在ovs bridge br-int内部交换即可,不需要经过物理网卡向外发包,两台云主机之间的带宽延时都非常低,网络性能主要依赖于物理机cpu能力和物理机负载情况。

在两台云主机的tap设备和物理网卡上抓包,发现只有tap设备有icmp数据包:

在云主机里ping网关10.0.70.1是可以在物理网卡上抓到包的:

 

同租户下不同宿主机上的两台云主机(同网段、同VLAN、不同物理机)

从物理机vs-compute-82上的云主机10.0.70.215 ping 物理机vs-compute-83上的云主机10.0.70.230。

两台云主机的tap设备就不抓包了,肯定有icmp数据包,这里只关注物理网卡p5p2:

可以看到两个物理机上的物理网卡都有icmp包经过(tap设备到br-int再到patch port再到br-p5p2最后从物理机82上出去,到物理机83上接收,转到br-p5p2,之后通过patch port转到br-int,最后到云主机tap设备)。其实一旦跨了物理机,就要经过物理交换机了,交换机那边我不熟悉,就不查看数据包流量了,同VLAN只需要进行二层交换即可。这种场景下两台云主机的网络带宽等性能更大程度上是受限于物理交换机的性能和负载。

不同租户下同一宿主机上的两台云主机(不同网段、不同VLAN、同物理机)

物理机为vs-controller,云主机在两个租户下,ip分别为10.0.80.38、10.0.70.32,使用不同的VLAN(ID分别为580和570),从10.0.80.38 ping 10.0.70.32。

两台云主机的tap设备都有icmp数据包,物理网卡p5p2也有,这种场景比上面的跨节点同网段多了一次三层路由过程,这个过程也是在物理交换机(路由器)上做的,因此整个过程类似从tap设备到br-int再到patch port再到br-p5p2再到物理网卡p5p2,之后到物理交换机(路由器)进行3层路由数据包(从VLAN 580到570),再从同一个物理网口返回物理机vs-controller的p5p2网卡,之后与发包过程反向进入另一台70段的云主机。

不同租户下同一宿主机上的两台云主机(不同网段、不同VLAN、不同物理机)

这个过程与上面的场景类似,不再分析,差异是到物理交换机(路由器)后是从另外一个网口出去到另外一台物理机的网卡。

租户私有网到公网

这个场景依赖物理交换机(路由器)配置好到私有网使用的VLAN的公网的出口网关和路由表,默认情况下,VLAN是无法连接到公网的。

整体过程与跨物理机的两台云主机之间通信类似,只不过云主机的数据包到物理交换机(路由器)之后,经过一次地址转换(SNAT)之后发送到公网网关(光猫),最终发到公网。

因为公司办公区机房没有公网IP,公网到云主机的网络流量就不分析了。

 

 

Open vSwitch OpenFlow流表规则及操作浅析

环境准备

操作系统:Centos7.2 64bit

软件:tcpdump(tcpdump-4.9.0-5)、openvswitch(openvswitch-2.7.2-3)、ping(iputils-20160308-10)、ip(iproute-3.10.0-54)、ifconfig(net-tools-2.0-0.22.20131004git)

网络环境:ovs bridge ovs-wp、netns ns0&ns1、ovs ports wp0&wp1,wp0 in ns0 with ip address 10.0.0.11,wp1 in ns1 with ip address 10.0.0.12,ovs-wp bridge with ip address 10.0.0.1

 

实验目标

理解

cookie=0x0, duration=314.876s, table=0, n_packets=0, n_bytes=0, idle_age=314, priority=1,in_port=100 actions=mod_nw_src:10.0.0.101,NORMAL

cookie=0x98cd36ade228396c, duration=16162.223s, table=71, n_packets=532, n_bytes=22344, idle_age=3, priority=95,arp,reg5=0xf,in_port=15,dl_src=fa:16:3e:0b:4c:49,arp_spa=10.0.70.52 actions=NORMAL

cookie=0x98cd36ade228396c, duration=16162.915s, table=71, n_packets=0, n_bytes=0, idle_age=16162, priority=70,udp,reg5=0x3546,in_port=13638,tp_src=67,tp_dst=68 actions=drop

各字段的意义和使用场景

操作步骤

创建ovs bridge:ovs-vsctl add-br ovs-wp

创建ovs port并添加到ovs bridge:

有两种方法,一种是分两步, ovs-vsctl add-port ovs-wp wp0先添加wp0 port,然后执行ovs-vsctl ovs-wp set Interface wp0 type=internal修改port类型为internal;第二种方法是一次执行完,ovs-vsctl add-port ovs-wp wp1 — set Interface wp1 type=internal

问题1:为啥要把port修改为internal类型?

查看ovs bridge信息:ovs-vsctl show

用ovs-ofctl命令查看:ovs-ofctl show ovs-wp

wp0前面的数字100就是OpenFlow port number。

创建netns: ip netns add ns0、 ip netns add ns1

移动port到netns:ip link set wp0 netns ns0、ip link set wp0 netns ns1

进入netns,设置ip地址:ip netns ns0 exec bash、ip addr add 10.10.0.11/24 dev wp0,ip netns ns1 exec bash、ip addr add 10.10.0.12/24 dev wp1

问题2:什么是netns?可以用来做什么?

设置ovs bridge的ip地址:ip addr add 10.0.0.1/24 dev ovs-wp

从root netns ping wp1(wp0也类似):

查看bridge上的流表信息:ovs-ofctl dump-flows ovs-wp

从wp0 ping wp1以及反方向测试连通性:先进入ns0,ip netns exec ns0 bash,之后执行ip a(ip addr简写),可以看到wp0虚拟网卡及其ip信息,

ping的过程中在ns1中使用tcpdump查看wp1上的数据包:

默认在netns中ping wp0、wp1自己的ip是不通的,原因是没有启用lo设备,启用后可以正常ping通:ifconfig lo up,之后再次执行ip a查看网络信息:

在ns0里ping wp0自己ip地址10.0.0.11过程中使用tcpdump查看lo设备网络数据包,可以看到有数据包,查看wp0虚拟网卡没有数据包,ping 127.0.0.1也一样,

问题3:为啥ping自己的ip(非lo设备上的127.0.0.1)必须要启用lo设备?

在ns0里ping ns1里wp1的ip 10.0.0.12过程中,查看两次ovs bridge流表,可以看到数据包数量和字节数有增加,停止ping之后保持不变,

n_packets=1849, n_bytes=161978,n_packets=1853, n_bytes=162370,多了4个包,并且idle_age也清零了。

问题4:n_packets、n_bytes、idle_age、hard_age的含义是啥?

流规则操作

添加一条规则,丢弃wp0到wp1的icmp协议包,让wp0 ping不通wp1:

方法1,用wp0的mac地址做为过滤条件:

添加完查看流表规则:

多出来一条新加的,进入ns0,执行ping 10.0.0.12,不通了:

问题5:dl_src、dl_type、nw_proto、action的含义是啥?

方法2,用OpenFlow Port Number作为过滤条件(先删除方法1的规则):

添加一条规则,修改wp0到wp1的数据包的源ip地址为1.2.3.4,并验证priority字段的用途:

再加一条优先级数字更大的,源ip改为2.3.4.5的规则:

priority数字越大表示越高,后加的这条优先级为priority=10的规则覆盖了之前的优先级为priority=1的,源ip修改为2.3.4.5:

从ns0、ns1 ping公网ip如114.114.114.114:

ip r查看路由信息,没有默认路由信息:

添加默认路由,之后还是不通,应该是ovs-wp这个bridge没有添加出口网卡设备,也没有配置相关的路由,相当于是无法连通公网的一个局域网。在ovs-wp加上eth0之后,把ovs-wp的mac改成eth0的,把eth0的改成其他的,用dhclient -v ovs-wp获取到之前eth0上的ip地址,默认路由也加回来了,在root netns ping外网地址可以通,但是在ns1里面还是不行,tcpdump看到数据包走到ovs-wp之后就没有再回来,eth0网卡没有数据包,添加流表规则,把wp1 port上的包都转到eth0所在的port,可以看到eth0上有包了,但是还是没有出去(ping 同网段的其他主机,在其他主机上tcpdump没看到有包过来),到此就不知道啥原因了,身边也没有可以请教的人,这个问题就先遗留吧。

流表规则还有几个字段的意义不太懂,

问题6:cookie、table、duration的含义是啥?

问题思考

问题1:为啥要把port修改为internal类型?

只有internal类型的port才能设置ip地址。

更多请参考:http://www.isjian.com/openstack/openstack-base-use-openvswitch/#port

问题2:什么是netns?可以用来做什么?

network namespace是Linux命名空间的一种,主要目的是为了实现网络隔离(隔离的网卡设备、独立的路由表)。

network namespace更多信息请参考:https://blog.scottlowe.org/2013/09/04/introducing-linux-network-namespaces/

Linux namespace介绍:https://coolshell.cn/articles/17010.html

问题3:为啥ping自己的ip(非lo设备上的127.0.0.1)必须要启用lo设备?

所有只在本机内部流转的网络数据包都需要经过lo设备的处理。

参考:http://blog.csdn.net/xie0812/article/details/32075613

问题4:n_packets、n_bytes、idle_age、hard_age的含义是啥?

n_packets、n_bytes,匹配到这条规则的网络包数、字节数。

idle_age:多久没有数据包经过这条规则,单位秒

hard_age:距这条规则创建、修改经过的时间,单位秒

参考:http://www.openvswitch.org//support/dist-docs/ovs-ofctl.8.txt

问题5:dl_src、dl_type、nw_proto、actions的含义是啥?

dl_src:datalink source,也就是源mac地址,对应的dl_dst就是目标mac地址。

dl_type:datalink type,也就是数据链路类型,

nw_proto:network protocol,也就是网络层协议。

actions:规则执行的操作,操作有很多种,可参考下面的链接。

具体可参考:https://www.ibm.com/developerworks/cn/cloud/library/1401_zhaoyi_openswitch/

问题6:cookie、table、duration的含义是啥?

cookie=0x98cd36ade228396c,一个64bit的整数,相同的cookie值可以用来标记是同一批或同一类规则。

table:流表编号,可以用来建立规则的层次关系,比如先经过0号表,之后actions里面指定继续匹配10号表的规则,如:

duration=secs,规则创建了多长时间。

最后唠叨一句,重启openvswitchd进程,会导致所有规则丢失,这也是OpenStack neutron项目很久才解决的一大难题。

参考: