Serf初体验

随着互联网的发展,尤其是最近几年的移动互联网,能接入网络的设备越来越多,访问量也越来越大,这也就需要越来越多的服务器,所以说现在IT公司的运维也发生了很大的变化。随之而来的是各种运维相关的理念、工具层出不穷。即使不做运维,你也总该听说过DevOps、Puppet、Chef这些东西吧。不过这里我们来介绍一个叫做Serf的东西。

Serf是什么呢,按照官方定义:

Serf is a service discovery and orchestration tool that is decentralized, highly available, and fault tolerant.

即它是一个服务发现,编配(应用集群管理等)工具,它去中心化,高可用并且能故障恢复(容忍)。

Serf使用Gossip协议,采用Go语言编写。

说起Serf,还要再顺便提一下Vagrant这个虚拟机管理用工具,因为这两个工具同出自一家公司:HashiCorp,这家公司还有一个产品交Packer(Packer是一个从配置文件为各种平台创建OS镜像的工具)。

Serf主要是为了解决下面几个问题:

・成员关系(Membership)

可以感知集群中各服务器的状态变化。

・故障检测和恢复

定期进行Serf agent活性检测,并尝试恢复。

・事件广播

Serf能在集群中广播各种事件(包括系统定义,用户自定义),你可以通过事件来做各种操作,比如部署,同步配置文件等。

下面我们就来按照它的入门文档简单体验一下吧。

1. 安装

这里不多说了,我的测试环境为HOST:Mac,通过Vagrant(VirtualBox)装了一台Ubuntu(GUEST)。
两个OS里都需要安装Serf软件,去这里下载即可,解压后就是一个可执行文件,直接放到PATH里即可。

注意:按照官方文档,即使是在同一台机器上,也可以启动若干个Serf的代理。不过我这里还是用了两个OS。

2. 配置

需要配置一下HOST和GUEST上的IP地址就行了。
比如HOST:10.10.10.1
GUEST:10.10.10.2

我的Vagrant配置文件如下:

Vagrant.configure('2') do |config|
  config.vm.box      = 'precise32'
  config.vm.box_url  = 'http://files.vagrantup.com/precise32.box'
  config.vm.hostname = 'rails-dev-box'

  config.vm.network :forwarded_port, guest: 3000, host: 3000
  config.vm.network :private_network, ip: "10.10.10.2"
  config.vm.provision :puppet do |puppet|
    puppet.manifests_path = 'puppet/manifests'
    puppet.module_path    = 'puppet/modules'
  end
end

3. 开始测试

3.1 启动Serf代理

首先,在HOST机器里先启动,命令如下

liubin:bin liubin$ serf agent -bind=10.10.10.1:7946 -log-level=debug -event-handler=handler.sh

注:SHELL里提示符为vagrant@rails-dev-box的都是在GUEST机器里。
SHELL里为liubin:bin liubin的都是在HOST机器里执行的。

bind的指定的是绑定地址。-event-handler=handler.sh指定了处理代理收到事件的脚本文件。

启动后打印出的日志如下:

==> Starting Serf agent…
==> Starting Serf agent RPC…
==> Serf agent running!
Node name: ‘liubin.local’
Bind addr: ‘10.10.10.1:7946’
RPC addr: ‘127.0.0.1:7373’
Encrypted: false
Snapshot: false
Profile: lan

==> Log data will now stream in as it occurs:

2014/02/22 18:28:22 [INFO] Serf agent starting
2014/02/22 18:28:22 [INFO] serf: EventMemberJoin: liubin.local 10.10.10.1
2014/02/22 18:28:23 [INFO] agent: Received event: member-join
2014/02/22 18:28:23 [DEBUG] Event ‘member-join’ script output:
New event: member-join. Data follows…
liubin.local10.10.10.1
2014/02/22 18:30:24 [INFO] agent.ipc: Accepted client: 127.0.0.1:54774
2014/02/22 18:30:58 [INFO] agent.ipc: Accepted client: 127.0.0.1:54944
2014/02/22 18:35:16 [INFO] memberlist: Responding to push/pull sync with: 10.10.10.2:56307

HOST上的代理启动之后,下面在GUEST上也启动代理服务,在这里没有指定事件处理脚本。

vagrant@rails-dev-box:~$ serf agent -bind=10.10.10.2:7946

==> Starting Serf agent…
==> Starting Serf agent RPC…
==> Serf agent running!
Node name: ‘rails-dev-box’
Bind addr: ‘10.10.10.2:7946’
RPC addr: ‘127.0.0.1:7373’
Encrypted: false
Snapshot: false
Profile: lan

==> Log data will now stream in as it occurs:

2014/02/22 10:30:44 [INFO] Serf agent starting
2014/02/22 10:30:44 [INFO] serf: EventMemberJoin: rails-dev-box 10.10.10.2
2014/02/22 10:30:45 [INFO] agent: Received event: member-join
2014/02/22 10:30:55 [INFO] agent.ipc: Accepted client: 127.0.0.1:57402

这时候,在两个OS上分别确认一下集群情况:
注:下面的操作都在各自新开的终端里执行。

vagrant@rails-dev-box:~$ serf members
rails-dev-box 10.10.10.2:7946 alive

liubin:bin liubin$ serf members
liubin.local 10.10.10.1:7946 alive

可见,它们都还只能看到自己。

3.2. 加入集群

在GUEST上执行serf join命令即可:

vagrant@rails-dev-box:~$ serf join 10.10.10.1:7946
Successfully joined cluster by contacting 1 nodes.

vagrant@rails-dev-box:~$ serf members
rails-dev-box 10.10.10.2:7946 alive
liubin.local 10.10.10.1:7946 alive

可以看到,GUEST机器里已经加入到HOST的集群里了,并且它们的状态都是alive

再到HOST上也确认一下。

liubin:bin liubin$ serf members
liubin.local 10.10.10.1:7946 alive
rails-dev-box 10.10.10.2:7946 alive
liubin:bin liubin$

我们也可以分别在它们启动Serf代理的终端里确认一下输出:

GUEST上的输出:

2014/02/22 10:35:16 [INFO] agent.ipc: Accepted client: 127.0.0.1:57403
2014/02/22 10:35:16 [INFO] agent: joining: [10.10.10.1:7946] replay: false
2014/02/22 10:35:16 [INFO] memberlist: Initiating push/pull sync with: 10.10.10.1:7946
2014/02/22 10:35:16 [INFO] serf: EventMemberJoin: liubin.local 10.10.10.1
2014/02/22 10:35:16 [INFO] agent: joined: 1 Err:
2014/02/22 10:35:17 [INFO] agent: Received event: member-join
2014/02/22 10:35:19 [INFO] agent.ipc: Accepted client: 127.0.0.1:57405
2014/02/22 10:35:22 [INFO] memberlist: Initiating push/pull sync with: 10.10.10.1:7946
2014/02/22 10:35:40 [INFO] memberlist: Responding to push/pull sync with: 10.10.10.1:56176

HOST上的输出:

2014/02/22 18:35:16 [INFO] serf: EventMemberJoin: rails-dev-box 10.10.10.2
2014/02/22 18:35:16 [DEBUG] serf: messageJoinType: rails-dev-box
2014/02/22 18:35:16 [DEBUG] serf: messageJoinType: rails-dev-box
2014/02/22 18:35:16 [DEBUG] serf: messageJoinType: rails-dev-box
2014/02/22 18:35:17 [DEBUG] serf: messageJoinType: rails-dev-box
2014/02/22 18:35:17 [INFO] agent: Received event: member-join

3.3 事件处理脚本

实际上上面的操作后,HOST上还有如下输出:

2014/02/22 18:35:17 [DEBUG] Event ‘member-join’ script output:
New event: member-join. Data follows…
rails-dev-box10.10.10.2

这就是在HOST上启动Serf代理时指定的脚本打印出来的。具体这个脚本的内容如下:


#!/bin/bash

echo
echo "New event: ${SERF_EVENT}. Data follows..."
while read line; do
    printf "${line}\n"
done


3.4. 停止代理运行

下面再来看看如果停止了一台机器会如何。

在GUEST上按ctrl+c,HOST上则会打印出如下消息。

2014/02/22 18:38:09 [DEBUG] serf: messageLeaveType: rails-dev-box
2014/02/22 18:38:10 [DEBUG] serf: messageLeaveType: rails-dev-box
2014/02/22 18:38:10 [DEBUG] serf: messageLeaveType: rails-dev-box
2014/02/22 18:38:10 [DEBUG] serf: messageLeaveType: rails-dev-box
2014/02/22 18:38:10 [INFO] serf: EventMemberLeave: rails-dev-box 10.10.10.2
2014/02/22 18:38:11 [INFO] agent: Received event: member-leave
2014/02/22 18:38:11 [DEBUG] Event ‘member-leave’ script output:
New event: member-leave. Data follows…
rails-dev-box10.10.10.2

即收到了一个member-leave的消息。

ctrl+c会导致Serf代理执行graceful shutdown,即给Serf代理了一个做收尾工作的机会。

这时候在HOST机器上看看集群的情况,GUEST里的代理状态由alive变为left了。如果在GUEST不是通过ctrl+c关闭代理的话,而是不如通过拔网线等,则这个集群代理的状态应该是failed。Serf集群里的节点会自动重连failed掉的节点,而对left的节点则不会。

liubin:bin liubin$ serf members
liubin.local 10.10.10.1:7946 alive
rails-dev-box 10.10.10.2:7946 left
liubin:bin liubin$

如果你手工停止了一个节点,如果你还想重新加入到集群的话,那么重启之后貌似还得手工执行serf join操作。(如果能自动应该方便不少吧?)

4. 感受

感觉Serf属于偏上层的一个在集群、应用之间进行协调管理的框架和自动化工具。节点之间通过消息(Event)来通信,比如可以在集群节点变化时通知负载均衡服务器,自动部署等。

附录:

1. 部分单词翻译

fault tolerant:故障容许

orchestration:编配(想不出别的合适的词了。出处见这里



Posted in go, Tech Tagged with: , , , , , ,

无觅相关文章插件,快速提升流量