声明:
本博客欢迎转发
内容系本人学习, 研究和总结,有些是摘抄自互联网,如有雷同,实属荣幸.

Git Flow 是什么

Git Flow是构建在Git之上的一个组织软件开发活动的模型,是在Git之上构建的一项软件开发最佳实践。Git Flow是一套使用Git进行源代码管理时的一套行为规范和简化部分Git操作的工具。

2010年5月,在一篇名为“一种成功的Git分支模型”的博文中,@nvie介绍了一种在Git之上的软件开发模型。通过利用Git创建和管理分支的能力,为每个分支设定具有特定的含义名称,并将软件生命周期中的各类活动归并到不同的分支上。实现了软件开发过程不同操作的相互隔离。这种软件开发的活动模型被nwie称为“Git Flow”。

一般而言,软件开发模型有常见的瀑布模型、迭代开发模型、以及最近出现的敏捷开发模型等不同的模型。每种模型有各自应用场景。Git Flow重点解决的是由于源代码在开发过程中的各种冲突导致开发活动混乱的问题。因此,Git flow可以很好的于各种现有开发模型相结合使用。

在开始研究Git Flow的具体内容前,下面这张图可以看到模型的全貌(引自nvie的博文):

Git Flow

Git Flow 中的分支

Git Flow模型中定义了主分支和辅助分支两类分支。其中主分支用于组织与软件开发、部署相关的活动;辅助分支组织为了解决特定的问题而进行的各种开发活动。

主分支

主分支是所有开发活动的核心分支。所有的开发活动产生的输出物最终都会反映到主分支的代码中。主分支分为master分支和development分支。

 Main

master分支

master分支上存放的应该是随时可供在生产环境中部署的代码(Production Ready state)。当开发活动告一段落,产生了一份新的可供部署的代码时,master分支上的代码会被更新。同时,每一次更新,最好添加对应的版本号标签(TAG)。

develop分支

develop分支是保存当前最新开发成果的分支。通常这个分支上的代码也是可进行每日夜间发布的代码(Nightly build)。因此这个分支有时也可以被称作“integration branch”。

当develop分支上的代码已实现了软件需求说明书中所有的功能,通过了所有的测试后,并且代码已经足够稳定时,就可以将所有的开发成果合并回master分支了。对于master分支上的新提交的代码建议都打上一个新的版本号标签(TAG),供后续代码跟踪使用。

因此,每次将develop分支上的代码合并回master分支时,我们都可以认为一个新的可供在生产环境中部署的版本就产生了。通常而言,“仅在发布新的可供部署的代码时才更新master分支上的代码”是推荐所有人都遵守的行为准则。基于此,理论上说,每当有代码提交到master分支时,我们可以使用Git Hook触发软件自动测试以及生产环境代码的自动更新工作。这些自动化操作将有利于减少新代码发布之后的一些事务性工作。

辅助分支

辅助分支是用于组织解决特定问题的各种软件开发活动的分支。辅助分支主要用于组织软件新功能的并行开发、简化新功能开发代码的跟踪、辅助完成版本发布工作以及对生产代码的缺陷进行紧急修复工作。这些分支与主分支不同,通常只会在有限的时间范围内存在。

辅助分支包括:

  • 用于开发新功能时所使用的feature分支;
  • 用于辅助版本发布的release分支;
  • 用于修正生产代码中的缺陷的hotfix分支。

以上这些分支都有固定的使用目的和分支操作限制。从单纯技术的角度说,这些分支与Git其他分支并没有什么区别,但通过命名,我们定义了使用这些分支的方法。

feature分支

使用规范:

可以从develop分支发起feature分支
代码必须合并回develop分支
feature分支的命名可以使用除master,develop,release-,hotfix-之外的任何名称
feature分支(有时也可以被叫做“topic分支”)通常是在开发一项新的软件功能的时候使用,这个分支上的代码变更最终合并回develop分支或者干脆被抛弃掉(例如实验性且效果不好的代码变更)。

一般而言,feature分支代码可以保存在开发者自己的代码库中而不强制提交到主代码库里

 Hotfix branch

release分支

使用规范:

  • 可以从develop分支派生
  • 必须合并回develop分支和master分支
  • 分支命名惯例:release-*

release分支是为发布新的产品版本而设计的。在这个分支上的代码允许做小的缺陷修正、准备发布版本所需的各项说明信息(版本号、发布时间、编译时间等等)。通过在release分支上进行这些工作可以让develop分支空闲出来以接受新的feature分支上的代码提交,进入新的软件开发迭代周期。

当develop分支上的代码已经包含了所有即将发布的版本中所计划包含的软件功能,并且已通过所有测试时,我们就可以考虑准备创建release分支了。而所有在当前即将发布的版本之外的业务需求一定要确保不能混到release分支之内(避免由此引入一些不可控的系统缺陷)。

成功的派生了release分支,并被赋予版本号之后,develop分支就可以为“下一个版本”服务了。所谓的“下一个版本”是在当前即将发布的版本之后发布的版本。版本号的命名可以依据项目定义的版本号命名规则进行。

 Release

hotfix分支

使用规范:

  • 可以从master分支派生
  • 必须合并回master分支和develop分支
  • 分支命名惯例:hotfix-*

除了是计划外创建的以外,hotfix分支与release分支十分相似:都可以产生一个新的可供在生产环境部署的软件版本。

当生产环境中的软件遇到了异常情况或者发现了严重到必须立即修复的软件缺陷的时候,就需要从master分支上指定的TAG版本派生hotfix分支来组织代码的紧急修复工作。

这样做的显而易见的好处是不会打断正在进行的develop分支的开发工作,能够让团队中负责新功能开发的人与负责代码紧急修复的人并行的开展工作。

 Release

使用md-write书写静态博客

插件安装

由于Atom插件的仓库在中国经常访问失败,因此我们使用源代码实施进行安装

  1. 安装md-writer插件

    1
    2
    3
    $ git clone https://github.com/zhuochun/md-writer
    $ cd md-writer
    $ npm install
  2. 安装markdown-pdf插件

    1
    2
    3
    $ git clone https://github.com/travs/markdown-pdf
    $ cd markdown-pdf
    $ npm install

Read More

声明:
本博客欢迎转发
内容系本人学习, 研究和总结,有些是摘抄自互联网,如有雷同,实属荣幸.

RabbitMQ 的基本概念

RabbitMQ 是实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。

AMQP 是一个定义了在应用或者组织之间传送消息的协议的开放标准 (an open standard for passing business messages between applications or organizations),它最新的版本是 1.0。AMQP 目标在于解决在两个应用之间传送消息存在的下列问题:

  • 网络是不可靠的 =>消息需要保存后再转发并有出错处理机制
  • 与本地调用相比,网络速度慢 =>得异步调用
  • 应用之间是不同的(比如不同语言实现、不同操作系统等) =>得与应用无关
  • 应用会经常变化 =>同上

AMQP 使用异步的、应用对应用的、二进制数据通信来解决这些问题。

RabbitMQ 是 AMQP 的一种实现,它包括Server (服务器端)、Client (客户端) 和 Plugins (插件)。RabbitMQ 服务器是用 Erlang 语言编写的,其最新版本是刚刚(2015/02/11)发布的 3.4.4,而 OpenStack Juno 中使用的 Server 是 2014年3月发布的 3.2.4 版本。现在 RabbitMQ 支持的 AMQP 版本依然是0.9.1。

RabbitMQ 的概念非常清晰、简洁

其基本概念参见下图:

RabbitMQ 官网 和其它网站上有很多文章来描述其基本概念。简单说明如下:

  • Message (消息):RabbitMQ 转发的二进制对象,包括Headers(头)、Properties (属性)和 Data (数据),其中数据部分不是必要的。具体见 1.2 部分的描述。
  • Producer(生产者): 消息的生产者,负责产生消息并把消息发到交换机 Exhange的应用。
  • Consumer (消费者):使用队列 Queue 从 Exchange 中获取消息的应用。
  • Exchange (交换机):负责接收生产者的消息并把它转到到合适的队列 Queue 。下面有 1.3 部分描述。
  • Queue (队列):一个存储Exchange 发来的消息的缓冲,并将消息主动发送给Consumer,或者 Consumer 主动来获取消息。见 1.4 部分的描述。

  • Binding (绑定):队列 和 交换机 之间的关系。Exchange 根据消息的属性和 Binding 的属性来转发消息。绑定的一个重要属性是 binding_key。

  • Connection (连接)和 Channel (通道):生产者和消费者需要和 RabbitMQ 建立 TCP 连接。一些应用需要多个connection,为了节省TCP 连接,可以使用 Channel,它可以被认为是一种轻型的共享 TCP 连接的连接。连接需要用户认证,并且支持 TLS (SSL)。连接需要显式关闭。

  • Virtual Host (虚拟主机) :RabbitMQ 用来进行资源隔离的机制。一个虚机主机会隔离用户、exchange、queue 等。默认的虚拟主机为 “/“。

关于消息 message

消息结构

消息的几个重要属性:

  • routing_key:Direct 和 Topic 类型的 exchange 会根据本属性来转发消息。
  • delivery_mode: 将其值设置为 2 将用于消息的持久化,持久化的消息会被保存到磁盘上来防止其丢失。下面章节 3 有描述。

  • reply_to:一般用来表示RPC实现中客户端的回调队列的名字。下面章节 4 有描述。

  • correlation_id:用于使用 RabbitMQ 来实现 RPC的情形。下面章节 4 有描述。
  • content_type:表示消息data的编码格式名称。实际上RabbitMQ只负责原样传送消息因此不会使用该属性,该属性只被 Publisher 和 Consumer 使用。

消息的确认/删除机制:

Consumer 处理消息可能会失败,那么 RabbitMQ 怎么知道什么时候来删除 queue 中的消息呢?它使用两种机制:

  • 当 RabbitMQ 主动将消息发给 Consumer 以后,它会删除消息
  • 当 Consumer 发回一个确认后,RabbitMQ 会删除消息。
    第二种情况下,如果 RabbitMQ 没收到确认,它会把消息重新放进队列(re-queued)并添加标识 ‘redelivered’ 表明该消息之前已经发送过 ,如果没有Consumer的话,消息将保持到有下一个 Consumer 为止。

Consumer 可以主动告诉 RabbitMQ 消息处理失败了(拒绝消息),并告知RabbitMQ 是删除消息还是重新放进队列。

exchange 交换机

exchange 有几个重要的属性:

  • Name 名字:交换机名字。空字符串名字的exchange为默认的exchange。
  • Type 类型:Direct, Fanout, Topic, Headers。类型决定 exchange 的消息转发能力。下面 章节2 有描述。
  • durable:值为 True/False。值为 true 的 exchange 在 rabbitmq 重启后会被自动创建。OpenStack 使用的exchange的该值都为false。
  • auto_delete:值为 True/False。设置为 true 的话,当所有消费者的连接都关闭后,该 exchange 会被自动删除。OpenStack 使用的exchange的该值都为false。
  • exclusive:值为 True/False。设置为 true 的话,该 exchange 只允许被创建的connection使用,并且在该 connection 关闭后它会被自动删除。

RabbitMQ 默认会为每一种类型生成一个或者两个的默认的 exchange:

  • Fanout 类型:名字为 amq.fanout
  • Topic 类型: 名字为 amq.topic
  • Headers 类型:名字为 amq.match 和 amq.headers
  • Direct 类型:名字为空字符串的exchange 以及 amq.direct。其中名字为空的exchange比较特殊。在一个 Queue 被创建后,RabbitMQ 会自动建立它和该 exchange 之间的binding,并且设置其 binding_key 为该queue 的名字。这样,该语句 channel.basic_publish(exchange=’’, routing_key=’hello’, body=message) 会让该默认的 exchange 将该 message 转发到名字为 ‘hello’ 的队列中。

队列 Queue

队列同样有类似于 exchange 的 name、durable、auto_delete 和 exclusive 等属性,并且含义相同。

Exchange 会将消息分发(copy)到符合要求的所有队列中。

Consumer 可以主动获取或者被动接受Queue里面的消息:

1
2
3
被动接收消息(订阅消息 "push API"):使用 basic.consume(short reserved-1, queue-name queue, consumer-tag consumer-tag,no-local no-local, no-ack no-ack, bit exclusive, no-wait no-wait,table arguments) 方法。见 5.1 示例代码。

主动获取消息 ("pull API"): 使用 basic.get(short reserved-1, queue-name queue, no-ack no-ack) 方法。

一个 Queue 允许有多个 Consumer,比如利用 RabbitMQ 来实现一个简单的 load balancer。这时候,消息会在这些 Consumer 之间根据 channel 的 prefetch level 做分发(请参见AQMP: QoS or message prefetching),如果该值一样的话,消息会被平均分发给这些Consumer。

rabbitmqctl Cli

RabbitMQ 提供Cli rabbitmqctl [-n ] [-q] [] 来进行管理和配置。常用到的命令有:

1
2
3
4
# stop/start_app
# add/delete/list_vhosts
# list_queues/exchanges/bindings/connections/channels
# trace_on/off

消息转发机制

Exchange 根据它自身的类型 type、消息的属性 routing_key 或者 headers,以及 Binding 的属性 binding_key 来转发消息。

Exchange 的类型 Type 使用的消息属性 使用的消息属性 转发模式
Fanout - (忽略消息的转发属性) -(忽略binding的转发属性) Exchange 将消息转发到所有与它有 binding 关系的队列中。这种方法转发效率较高。
OpenStack 大量使用这种类型的 exchange。
Direct routing_key (任意的字符串,比如 “abc”) binding_key (任意的字符串,比如 “abc”) Exchange 只将消息转到 binding 的 binding_key 等于消息的 routing_key 的队列中。
Topic Exchange 只将消息转到 binding 的 binding_key 等于消息的 routing_key 的队列中。 binding_key (包含 “#” 和 “*“ 的以 “.” 分割的多单词字符串,比如 *.efg.* Exchange 只将消息转到消息的 routing_key 和 binding 的 binding_key 匹配的队列中。匹配规则如下:
1. 两者以”.”分割的单词数目相同
2. “*”可代表一个单词
3. “#“可代表零个或多个单词
Headers headers (消息头) binding_key Exchange 只将消息转到消息的 headers 和 binding 的 binding_key 匹配的队列中。匹配规则待研究。

持久化

消息的持久化意味着在 RabbitMQ 被重启后,消息依然还在。要实现持久化,得实现几个相关组件的持久化:

  1. 交换机的持久化,需要将其 durable 属性设为 true。chan.exchange_declare(exchange=”sorting_room”, type=”direct”, durable=True, auto_delete=False,)
  2. 队列的持久化,需要将其 durable 属性设置为 true。chan.queue_declare(queue=”po_box”, durable=True, exclusive=False, auto_delete=False)
  3. 消息的持久化,需要将其 Delivery Mode 属性设置成2 。msg.properties[“delivery_mode”] = 2

RPC

可以使用 RabbitMQ 来实现 RPC 机制,这里说说其实现原理:

过程:

  1. 客户端 Client 设置消息的 routing key 为 Service 的队列 op_q;设置消息的 reply-to 属性为返回的 response 的目标队列 reponse_q,设置其 correlation_id 为以随机UUID,然后将消息发到 exchange。比如:

    1
    2
    3
    channel.basic_publish(exchange='', routing_key='op_q',
    properties=pika.BasicProperties(reply_to = reponse_q, correlation_id = self.corr_id),
    body=request)
  2. Exchange 将消息转发到 Service 的 op_q

  3. Service 收到该消息后进行处理,然后将response 发到 exchange,并设置消息的 routing_key 为原消息的 reply_to 属性,以及设置其 correlation_id 为原消息的 correlation_id 。

    1
    2
    3
    ch.basic_publish(exchange='', routing_key=props.reply_to,
    properties=pika.BasicProperties(correlation_id = props.correlation_id),
    body=str(response))
  4. Exchange 将消息转发到 reponse_q

  5. Client 逐一接受 response_q 中的消息,检查消息的 correlation_id 是否为等于它发出的消息的correlation_id,是的话表明该消息为它需要的response。

这里有详细的描述

声明:
本博客欢迎转发
内容系本人学习, 研究和总结,有些是摘抄自互联网,如有雷同,实属荣幸.

文件系统

ext4

linux kernel 自2.6.28 开始正式支持新的文件系统Ext4, 比前面的Ext3系统有很多增强,因此也是默认使用的文件系统.

Btrfs:

Ceph-Osd在Btrfs上面有最佳的性能,支持Copy-On-Write, Writable snapshots. 问题是该文件系统显示还不是Production Ready, 不适合生产环境部署, 主要使用来作为测试.

XFS

日志文件系统, 使Ceph系统中使用最多的文件系统,也是作为Ceph-OSD推荐使用的文件系统.

Read More

声明:
本博客欢迎转发
内容系本人学习, 研究和总结,有些使摘抄自互联网,如有雷同,实属荣幸.

网络流量监控

iftop

iftop_interface

界面相关说明:

界面上面显示的是类似刻度尺的刻度范围,为显示流量图形的长条作标尺用的。

中间的<= =>这两个左右箭头,表示的是流量的方向。

TX:发送流量
RX:接收流量
TOTAL:总流量
Cumm:运行iftop到目前时间的总流量
peak:流量峰值
rates:分别表示过去 2s 10s 40s 的平均流量

Read More

声明:
本博客欢迎转发
内容系本人学习, 研究和总结,有些使摘抄自互联网,如有雷同,实属荣幸.

虚拟机硬盘格式比较

1. raw

raw格式是最简单,什么都没有,所以叫raw格式。连头文件都没有,就是一个直接给虚拟机进行读写的文件。raw不支持动态增长空间,必须一开始就指定空间大小。所以相当的耗费磁盘空间。但是对于支持稀疏文件的文件系统(如ext4)而言,这方面并不突出。ext4下默认创建的文件就是稀疏文件,所以不要做什么额外的工作。

raw镜像格式是虚拟机种I/O性能最好的一种格式,大家在使用时都会和raw进行参照,性能越接近raw的越好。但是raw没有任何其他功能。对于稀疏文件的出现,像qcow这一类的运行时分配空间的镜像就没有任何优势了。 Raw 的优势

  1. 简单,并能够到处为其他虚拟机虚拟硬盘格式
  2. 根据实际使用量来占用空间,而非设定的最大值(需要宿主支持hole)
  3. 能够被宿主机挂载, 不用开虚拟机即可在宿主和虚拟机间进行数据传输

Read More

声明:
本博客欢迎转发
内容系本人学习, 研究和总结,有些使摘抄自互联网,如有雷同,实属荣幸.

需求

在云计算数据中心,一台宿主机上面要跑几十台的VM,如果一台VM运行了大量IO,或者CPU密集的任务,如何保证其他的VM的服务质量呢? 这样我们就需要限制VM的能力,来保证Qos.

实现

1. CPU Qos

在Openstack Grizzly版本中已经继承了一个叫做 Instance Resource Quota的功能.这个功能基于cgroup和tc实现了CPU,disk IO和network IO的限流功能.Openstack在设置Flavor的时候,可以将这些限流信息设定好.当启动虚机的时候,写入/var/lib/nova/instance/xxx/libvirt.xml中就可以了.

我们可以大致测试一下,CPU的限制目前支持一下参数:

1
2
3
quota:cpu_shares
quota:cpu_period
quota:cpu_quota

通过CLI创建Flavor,并设置flavor的extra specs, 当然也可以通过dashboard设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[root@node-15 rabbitmq]# nova flavor-create cpu-quota-test 88 512 1 1
+----+----------------+-----------+------+-----------+------+-------+-------------+-----------+
| ID | Name | Memory_MB | Disk | Ephemeral | Swap | VCPUs | RXTX_Factor | Is_Public |
+----+----------------+-----------+------+-----------+------+-------+-------------+-----------+
| 88 | cpu-quota-test | 512 | 1 | 0 | | 1 | 1.0 | True |
+----+----------------+-----------+------+-----------+------+-------+-------------+-----------+
[root@node-15 rabbitmq]# nova flavor-key 88 set quota:cpu_period=5000
[root@node-15 rabbitmq]# nova flavor-key 88 set quota:cpu_quota=2500
[root@node-15 rabbitmq]# nova flavor-show 88
+----------------------------+---------------------------------------------------------+
| Property | Value |
+----------------------------+---------------------------------------------------------+
| OS-FLV-DISABLED:disabled | False |
| OS-FLV-EXT-DATA:ephemeral | 0 |
| disk | 1 |
| extra_specs | {"quota:cpu_period": "5000", "quota:cpu_quota": "2500"} |
| id | 88 |
| name | cpu-quota-test |
| os-flavor-access:is_public | True |
| ram | 512 |
| rxtx_factor | 1.0 |
| swap | |
| vcpus | 1 |
+----------------------------+---------------------------------------------------------+

然后使用这个flavor启动虚拟机,在计算节点上查看cgroup如下:

1
2
3
4
5
6
[root@node-21 vcpu0]# pwd
/cgroup/cpu/machine/instance-0000013e.libvirt-qemu/vcpu0
[root@node-21 vcpu0]# cat cpu.cfs_period_us
5000
[root@node-21 vcpu0]# cat cpu.cfs_quota_us
2500

默认的cpu period 使100000,这里已经改成5000,说明起作用了

参看libvirt.xml

1
2
3
4
5
6
7
[root@node-21 7e52545a-5e37-4bab-8dd4-46c6b906436e]# pwd
/var/lib/nova/instances/7e52545a-5e37-4bab-8dd4-46c6b906436e

<cputune>
<quota>2500</quota>
<period>5000</period>
</cputune>

Read More

声明:
本博客欢迎转发
内容系本人学习, 研究和总结,有些是摘抄自互联网,如有雷同,实属荣幸.

需求

通常在一个云计算中心中,提供虚拟资源池计算能力的物理主机一般有成百上千个,因为业务的需求,我们需要将这些物理主机进行分组,以区分其本身的性质或者提供不同的服务. 我们研究的使Openstack,因此这里就讨论Openstack中Nova如果通过配置将虚拟机创建到指定的Host或者分组中.

实现原理

当你发起一个创建虚机的请求,nova收到你的请求并分析所携带的创建约束条件,然后过滤出满足条件的主机,并在这些主机上创建虚机,这个过程主要有nova-scheduler 实现的. 最有主机的选择过程实际上就两个步骤,过滤和称重.

主机过滤

如上图,Filter Scheduler 首先得到未经过滤的主机列表,然后根据过滤属性,选择主机创建指定数目的虚拟机.

Nova中已经实现了多种的过滤策略,开发者也可以根据自己的需求来实现自己的过滤策略.

在/etc/nova/nova.conf中的scheduler_default_filter配置了起作用的filter

Read More

前言

  1. 什么是availablitiy_zone
    az 是用户可见的,用来手动的指定VM运行在哪些Host上. az 是在region范围内再次切分,例如可以吧一个机架上的机器划分在一个az中,划分az是为了提高容灾性和提供廉价的隔离服务。选择不同的region主要考虑那个region靠近你的用户群体。

  2. 什么是aggregate host
    host aggregate 是管理员用来根据硬件资源的某一属性对硬件进行划分的功能,只对管理员可见. 其主要功能就是实现根据某一属性来划分物理机,比如按照地理位置,使用固态硬盘的机器,内存超过32G的机器,根据这些指标来构成一个Host Group

在创建一个VM的时候,可以选择一个可用域,这样可以使创建的虚拟机位于可用域的Host机器上. 那么如何配置一个Host属于那个Availability Zone呢?

G版本的实现

在G版本中Service表中不在保存Availability_zone字段,配置项node_available_zone也不在使用.那么这时,如何确定一个host属于那个zone呢?

G版中,默认情况下,对Nova的服务分为两类,一类使Controller节点的服务进程,如nova-api, nova-scheduler, nova-conductor等,另一类使计算节点的进程, nova-computer. 对于第一类服务,默认的zone使配置项internal_service_availability_zone, 而nova-computer所属的zone配置项default_available_zone决定.

Read More