标签 redis 下的文章

Rancher使用入门

上个月末,Rancher Labs在其官方博客上宣布了 Rancher 1.0正式版本发布。 这是继Apache MesosGoogle Kubernetes以及Docker 原生 Swarm 之后,又一个可用于Production环境中的容器管理和服务编排工具,而Rancher恰似这个领域的最后一张拼图(请原谅我的孤陋寡闻,如 果有其他 厂商在做这方面产品,请在评论中留言告诉我)。从Rancher Labs的官方about中我们可以看到:Rancher Labs致力于为DevOps team打造一个最好的容器管理平台,让容器的部署和管理变得更加Easy。

本文将带大家与Rancher来个亲密接触,直观的体会一下Rancher的入门级使用方法。

注意:由于Rancher还在active development中,本文仅适用于刚刚发布的v1.0.0版本,包括:

rancher/server:v1.0.0
rancher/agent:v0.11.0
rancher/agent-instance:v0.8.1
rancher-compose-v0.7.3

后续版本演进可能会导致本文中某些操作不再适用或某些UI元素发生变化。

零、实验环境

这里继续使用之前文章中的两个Ubuntu 14.04主机环境(kernel版本 >= 3.16.7),Docker 1.9.1+。

其中:

rancher server:
    10.10.126.101

rancher agents:
    10.10.126.101
    10.10.105.71
    10.10.105.72

一、搭建单节点Rancher Server

Rancher的各种容器管理理念均架构在由Rancher server和rancher agent构建的Infrastructure之上。Rancher server是Rancher的核心,其地位就类似于k8s、Docker swarm或mesos中的master,提供核心容器管理服务以及API服务。作为正式版发布的Rancher v1.0.0支持HA(high available)的多节点rancher server集群,不过Install起来也的确复杂些,依赖的第三方组件也较多,什么MySQLRedisZooKeeper等统统都要额外部署。由于是入门,这里就偷个赖儿,我们就搭建一个单节点的Rancher Server。

Rancher的一个设计理念是所有组件都Containerized(容器化),更有甚者Rancher Labs的另外一个产品RancherOS(地位类似于CoreOS,一款专门为运行容器而设计的Linux发行版)中所有系统服务都是 Dockerized的,这里的Rancher Server也不例外,极大的方便了我们的Install。

下面我们就在126.101 host上安装一个Rancher server。

首先,我们将rancher/server image pull到local,这个image size很大,需要耐心等待一段时间,即便是使用国内容器云厂商提供的加速器:

$ docker pull rancher/server
... ...

$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
rancher/server      latest              26bce58807d1        22 hours ago        775.9 MB

接下来,启动rancher server:

$ docker run -d --restart=always -p 8080:8080 rancher/server
d8ce1654ff9f1d056d7cdc9216cf19173d85037bf23be44f802d627eabc8e607

$ docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                              NAMES
d8ce1654ff9f        rancher/server      "/usr/bin/s6-svscan /"   12 seconds ago      Up 8 seconds        3306/tcp, 0.0.0.0:8080->8080/tcp   agitated_ardinghelli

映射的8080端口既服务于Rancher UI,也是Rancher API的服务端口。用浏览器打开http://10.10.126.101:8080,如果你看到如下页面,则说明你的Rancher Server搭建成功了:

img{512x368}

Rancher image size之所以大,是因为其内部安装和运行了诸多服务程序,我们来hack一下:

$ docker exec d8ce1654ff9f ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0    188     4 ?        Ss   03:50   0:00 /usr/bin/s6-svscan /service
root         5  0.0  0.0    188     4 ?        S    03:50   0:00 s6-supervise cattle
root         6  0.0  0.0    188     4 ?        S    03:50   0:00 s6-supervise mysql
root         7  6.5 18.1 3808308 710284 ?      Ssl  03:50   1:05 java -Xms128m -Xmx1024m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/lib/cattle/logs -Dlogback.bootstrap.level=WARN -cp /usr/share/cattle/9283c067b6f96f5ff1e38fb0ddfd8649:/usr/share/cattle/9283c067b6f96f5ff1e38fb0ddfd8649/etc/cattle io.cattle.platform.launcher.Main
mysql       28  0.4  2.3 2135756 92164 ?       Ssl  03:50   0:04 /usr/sbin/mysqld --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib/mysql/plugin --user=mysql --log-error=/var/log/mysql/error.log --pid-file=/var/run/mysqld/mysqld.pid --socket=/var/run/mysqld/mysqld.sock --port=3306
root       170  0.1  0.2 264632 11552 ?        Sl   03:52   0:01 websocket-proxy
root       179  0.0  0.2 274668  8632 ?        Sl   03:52   0:00 rancher-catalog-service -catalogUrl library=https://github.com/rancher/rancher-catalog.git,community=https://github.com/rancher/community-catalog.git -refreshInterval 300
root       180  0.0  0.3 254044 12652 ?        Sl   03:52   0:00 rancher-compose-executor
root       181  0.5  0.4 1579572 16692 ?       Sl   03:52   0:05 go-machine-service
root       610  0.0  0.0  14988  2576 ?        S    04:06   0:00 git -C ./DATA/library pull -r origin master
root       611  0.0  0.0   4448  1696 ?        S    04:06   0:00 /bin/sh /usr/lib/git-core/git-pull -r origin master
root       640  0.0  0.0  15024  3020 ?        S    04:06   0:00 git fetch --update-head-ok origin master
root       641  3.0  0.1 161180  6028 ?        S    04:06   0:00 git-remote-https origin https://github.com/rancher/rancher-catalog.git
root       643  0.0  0.0  15572  2120 ?        Rs   04:07   0:00 ps aux

可以看出里面有mysql、cattle、go-machine-service、rancher-compose-executor以及 websocket-proxy等。通过PID我们可以看出/usr/bin/s6-svscan是容器的第一个启动进程,/service这个 路径作为其命令行参数,估计这是一个类似于supervisord的进程控制程 序,由其 负责启动和管理Rancher server的两个重要服务:MySQL和cattle。注:单节点rancher server的数据都保存在其内部的MySQL中,而多节点rancher server则采用一个外部的MySQL存储数据。

二、设置Account

第一次启动Rancher后,Rancher的UI是没有访问控制的,所有人都可以访问这个地址并控制一切。

切换到API菜单,可以看到当前默认Environment(后续会详细说这个概念)的API访问endpoint是: http://10.10.126.101:8080/v1/projects/1a5

我们可以用curl来访问一下这个url:

$ curl http://10.10.126.101:8080/v1/projects/1a5
{"id":"1a5","type":"project","links":{"self":"http://10.10.126.101:8080/v1/projects/1a5","agents":"http://10.10.126.101:8080/v1/projects/1a5/agents","auditLogs":"http://10.10.126.101:8080/v1/projects/1a5/auditlogs","certificates":"http://10.10.126.101:8080/v1/projects/1a5/certificates",
... ...
"swarm":false,"transitioning":"no","transitioningMessage":null,"transitioningProgress":null,"uuid":"adminProject"}

返回超过一屏的信息,这同时也说明Rancher Server在正常工作。

在正式感受Rancher功能前,我们来给Rancher添加一个Account,相信这也是所有要在生产环境使用Rancher的朋友必须要做 的事情。

在Rancher UI中,也许你已经注意到了,在第一行菜单栏中,“ADMIN”菜单项右侧有一个红色的“!”,这也是在提醒你Rancher当前未设防。我们点击 “ADMIN”,选择出现的二级菜单中的”ACCOUNTS”菜单项,我们将看到如下页面:

img{512x368}

添加权限控制,需要在【”ADMIN” -> “ACCESS CONTROL”】中。Rancher支持四种权限控制方案,分别是:Active Directory、GitHub、Local Auth和OpenLDAP。我们使用最简单的Local Auth,即设置一个用户名和密码,然后点击“Enable Local Auth”按钮即可。然后我们再回到”ACCOUNTS”页面:

img{512x368}

可以看到我们已经建立了一个新的Admin权限的账号:tonybai。当前的登录账号也换成了tonybai。

这时如果你再用API访问当前默认环境的EndPoint的话,结果就会变成下面这样:

 curl http://10.10.126.101:8080/v1/projects/1a5
{"id":"b052db07-d58e-45bf-872e-06ced8bcc4e1","type":"error","links":{},"actions":{},"status":401,"code":"Unauthorized","message":"Unauthorized","detail":null}

提示错误:Unauthorized

这时如果还想用API访问,就需要为该环境添加一个API Key了。在”API”页面下,点击 “Add Environment API Key”按钮,在弹出的窗口中输入key的name:tonybai-default-env-key,点击”Create”创建:

img{512x368}

Rancher会随机生成一对access key和secret key,即user和password,使用它们即可通过API访问该环境,注意:secret key只显示这么一次,你需要手工将其记录下来,否则一旦关闭这个窗口,就无法再找到secret key的内容了,只能再重新生成一对。

$curl -u 5569108BE7489DEE47A5:76Yw5v63ag8SdKYQDYgVok7Co6HRncU7bUCEShXh http://10.10.126.101:8080/v1/projects/1a5
{"id":"1a5","type":"project","links":{"self":"http://10.10.126.101:8080/v1/projects/1a5","agents":"http://10.10.126.101:8080/v1/projects/1a5/agents","auditLogs":"http://10.10.126.101:8080/v1/projects/1a5/auditlogs","certificates":"http://10.10.126.101:8080/v1/projects/1a5/certificates",
... ...
"swarm":false,"transitioning":"no","transitioningMessage":null,"transitioningProgress":null,"uuid":"adminProject"}

三、Environment

前面说过,Rancher中有个概念是Environment。在Rancher UI的右上角,我们可以看到”Default Enviromnet”字样,点击向下箭头,打开下拉菜单,选择:“Manage Enviromnets”,可以看到当前的Enviroments列表:

img{512x368}

在这个页面,我们可以看到Rancher对Enviroments的诠释:

Rancher supports grouping resources into multiple environments. Each one gets its own set of services and infrastructure resources, and is owned by one or more GitHub users, teams or organizations.

For example, you might create separate "dev", "test", and "production" environments to keep things isolated from each other, and give "dev" access to your entire organization but restrict the "production" environment to a smaller team.

大致意思就是一个Environment就是一个resource group,每个Environment都有自己的服务和基础设施资源,并且通过Access Control来赋予每个Account访问该Environments的权限。Rancher Labs的一个目标就是为DevOps Team打造一个Easy的容器管理工具,因此在解释Environment术语时,还特地以DevOps Workflow来解释,比如建立dev、test、production environment,保证Environments间的隔离。下面的这幅图可能会更直观的展现出Environment在Rancher中的“角 色”:

img{512x368}

Rancher Server建立后,会建立一个”Default” Environment,我们可以Edit一下这个Environment的信息,可以修改它的Name、Container Orchestration引擎(cattle、k8s和swarm,默认cattle)以及Access Control,我们看到tonybai的用户是这个Environment的Owner,当然我们也可以修改tonybai这个用户的Role,比如 member、readonly或restricted。这里我们将Default的名字改为”dev”。

我们再添加一个Environment “test”,引擎用cattle:

img{512x368}

我们看到dev environment后面有一个”对号”,说明dev environment是当前active environment,所有操作均针对该environment,你当然可以通过点击每个environment列表后面的切换图标来切换active environment。

到目前为止,虽然Rancher Server建立ok了,environment这个逻辑实体也建立了,但dev environment仍处于“无米下炊”的状态。因为除了Rancher自身外,该Environment下没有任何Resources(主机、存储 等)可供使用(比如创建Containers)。

我们来为dev environment添加两个主机资源:10.10.126.101和10.10.105.72。在”INFRASTRUCTURE”-> HOSTS中点击”Add Host”按钮添加主机资源。Rancher支持多种主机资源,包括Custom(本地自定义)、Amazon EC2Azure 以及 DigitalOcean 等。

我们以本地Host资源(选择Custom)为例,在添加Host页面中,我们输入第一个Host的IP,Rancher UI会生成下面这段命令行:

sudo docker run -e CATTLE_AGENT_IP='10.10.126.101'  -d --privileged -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/rancher:/var/lib/rancher rancher/agent:v0.11.0 http://10.10.126.101:8080/v1/scripts/B0C997705263867F519F:1460440800000:1Rd9TyJIS2Fnae5lcjsvnIRDJE

我们需要手动在10.10.126.101这个Host上执行上述命令行:

$ sudo docker run -e CATTLE_AGENT_IP='10.10.126.101'  -d --privileged -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/rancher:/var/lib/rancher rancher/agent:v0.11.0 http://10.10.126.101:8080/v1/scripts/B0C997705263867F519F:1460440800000:1Rd9TyJIS2Fnae5lcjsvnIRDJE
2d05764d42c52b1449021766a5c0e104098605cd7d53b632571c46f1e84f2a4b

$ docker ps
CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS              PORTS                              NAMES
2d05764d42c5        rancher/agent:v0.11.0   "/run.sh http://10.10"   27 seconds ago      Up 22 seconds                                          big_bhabha
d8ce1654ff9f        rancher/server          "/usr/bin/s6-svscan /"   4 days ago          Up 4 days           0.0.0.0:8080->8080/tcp, 3306/tcp   agitated_ardinghelli

等待一会儿,我们刷新一下”INFRASTRUCTURE”-> HOSTS页面,我们会看到10.10.126.101这个Host被加入到dev environment的Infrastructure中了:

img{512x368}

按照同样的步骤,我们再将10.10.105.72加入到Infrastructure中:

$ sudo docker run -e CATTLE_AGENT_IP='10.10.105.72'  -d --privileged -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/rancher:/var/lib/rancher rancher/agent:v0.11.0 http://10.10.126.101:8080/v1/scripts/B0C997705263867F519F:1460440800000:1Rd9TyJIS2Fnae5lcjsvnIRDJE
e1f335c665853348810aef8736c67f610ae7f4c93e4b6265361b95a354af434a

$docker ps
CONTAINER ID        IMAGE                   COMMAND                  CREATED             STATUS                  PORTS               NAMES
2e212fda35d3        rancher/agent:v0.11.0   "/run.sh inspect-host"   23 seconds ago      Up Less than a second                       trusting_noyce
e1f335c66585        rancher/agent:v0.11.0   "/run.sh http://10.10"   39 seconds ago      Up 23 seconds                               clever_bohr

我们注意到:上面的命令启动了两个Container,image虽然都是rancher/agent:v0.11.0,但执行的命令行参数略有 不同(其中一个Container为临时Container,一段时间后会自动退出)。片刻,我们就在Hosts下看到了两个Host资源了。

我们点击Rancher UI右上角的下拉箭头,将当前Environment从dev切换到test,我们发现test Environment下的Hosts又为空了(不过此处似乎有个bug,在我的Mac Chrome浏览器中,等的时间足够久后,似乎test environment把dev enviroment的Host资源显示出来了,很怪异)。可以看出Infra是Environment相关的。我们在test环境下增加一个 10.10.105.71 host:

$ sudo docker run -e CATTLE_AGENT_IP='10.10.105.71'  -d --privileged -v /var/run/docker.sock:/var/run/docker.sock -v /var/lib/rancher:/var/lib/rancher rancher/agent:v0.11.0 http://10.10.126.101:8080/v1/scripts/A63B9C5F8066E29377C3:1460448000000:UbPcmDXOqoI6mls6e75Qp17QR0
4a5f9e13615e562636cd515763e293449607a8b2d827d2599f80f9ad8f16aa2d

$ docker ps
CONTAINER ID        IMAGE                   COMMAND                  CREATED              STATUS                  PORTS                    NAMES
d101095c7709        rancher/agent:v0.11.0   "/run.sh run"            6 seconds ago        Up Less than a second                            rancher-agent
4a5f9e13615e        rancher/agent:v0.11.0   "/run.sh http://10.10"   About a minute ago   Up About a minute                                evil_khorana

到这里,test Environment下也有了一个Host了,从Rancher UI页面可以看到。

四、Stack

Rancher UI的左上角APPLICATIONS下面有一个“STACKS”的二级菜单项。Rancher官方docs对Stack的解释是:”A Rancher stack mirrors the same concept as a docker-compose project. It represents a group of services that make up a typical application or workload.”。同时Rancher UI上关于Service的解释如下:“A service is simply a group of containers created from the same Docker image but extends Docker’s “link” concept to leverage Rancher’s lightweight distributed DNS service for service discovery”。从这两段描述中,我们大致可以推出如下关系:

A Stack <=> An Application <=> A group of services(由类docker-compose的工具rancher-compose管理)

下面这幅图直观描述了user account, environment与stacks之间的关系:

img{512x368}

我们在dev environment下添加一个Service。Rancher UI “APPLICATIONS” -> “STACKS”下面支持两种添加Service的方式,一种是手工添加,一种是从Catalog添加。Catalog类似于一个Rancher App Market,里面有Rancher预定义好的service template。我们这次采用手工添加的方式,便于控制。我们基于nginx:1.8-alpine创建单一实例的service: nginx-alpine-service,端口映射:10086->80。其他采用默认配置。添加Service时,并没有位置让你为Stack 起名,但添加一个Service后,我们会看到当前Stack是Default Stack,你可以修改Stack name,这里改为nginx-app-stack。启动后,我们看到第一个nginx-alpine-service的Container运行在 105.72上。

img{512x368}

点击stack名字,可以查看stack的详细信息:

img{512x368}

点击”nginx-alpine-service”,进入到service属性页面,我们将nginx-alpine-service的 Scale +1。Rancher会自动在Resource host上根据默认调度策略,运行一个新的基于nginx image的Container。我们可以看到这个新Container运行在126.101上,这样dev Environmnet中的两个Host上就各自运行了一个nginx-alpine-service的Container:

img{512x368}

nginx-alpine-service的两个容器分别为:

 Running    Default_nginx-alpine-app_1  10.42.96.91 10.10.105.72  nginx:1.8-alpine
 Running    nginx-app-stack_nginx-alpine-service_1  10.42.164.174   10.10.126.101 nginx:1.8-alpine

Rancher内置“Internal DNS Services”,同一Stack下的Container可以通过Container name相互ping通。Rancher以Environment为界限,每个Environment下的Container name都是全局唯一的。

在10.10.105.72上,我们执行如下命令来ping 10.10.126.101上的容器:nginx-app-stack_nginx-alpine-service_1:

$ docker exec r-Default_nginx-alpine-app_1  ping -c 3 nginx-app-stack_nginx-alpine-service_1
PING nginx-app-stack_nginx-alpine-service_1 (10.42.164.174): 56 data bytes
64 bytes from 10.42.164.174: seq=0 ttl=62 time=0.729 ms
64 bytes from 10.42.164.174: seq=1 ttl=62 time=0.754 ms
64 bytes from 10.42.164.174: seq=2 ttl=62 time=0.657 ms

--- nginx-app-stack_nginx-alpine-service_1 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.657/0.713/0.754 ms

在10.10.126.101上,我们执行如下命令来ping 10.10.105.72上的容器:Default_nginx-alpine-app_1:

$ docker exec r-nginx-app-stack_nginx-alpine-service_1 ping -c 3 Default_nginx-alpine-app_1
PING Default_nginx-alpine-app_1 (10.42.96.91): 56 data bytes
64 bytes from 10.42.96.91: seq=0 ttl=62 time=0.640 ms
64 bytes from 10.42.96.91: seq=1 ttl=62 time=0.814 ms
64 bytes from 10.42.96.91: seq=2 ttl=62 time=0.902 ms

--- Default_nginx-alpine-app_1 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.640/0.785/0.902 ms

我们按照上述方法为nginx-app-stack再添加一个Service: redis-alpine-service,该service基于redis:alpine image,该service的Container被运行在105.72上了:

$ docker ps
CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS              PORTS                                          NAMES
7246dce88ea6        redis:alpine                    "/entrypoint.sh redis"   3 minutes ago       Up 3 minutes        6379/tcp                                       r-nginx-app-stack_redis-service_1

我们来测试一下同一stack下,不同Service的互ping:

我们在redis-alpine-service的Container中来ping nginx-alpine-service,地址直接使用”nginx-alpine-service”这个service name即可:

$ docker exec r-nginx-app-stack_redis-service_1 ping -c 3 nginx-alpine-service
PING nginx-alpine-service (10.42.164.174): 56 data bytes
64 bytes from 10.42.164.174: seq=0 ttl=62 time=0.660 ms
64 bytes from 10.42.164.174: seq=1 ttl=62 time=0.634 ms
64 bytes from 10.42.164.174: seq=2 ttl=62 time=0.599 ms

--- nginx-alpine-service ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.599/0.631/0.660 ms

可以看到Rancher的Internal DNS Service将”nginx-alpine-service”这个service name解析为nginx-alpine-service的两个Container中的一个:10.42.164.174。

我们再添加一个Stack:memcached-app-stack,来看一下跨Stack的容器连通方法。ping之前我们需要为该Stack添加一个基于memcached:latest image的Service: memcached-service

10.10.105.72

$ docker ps
CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS              PORTS                                          NAMES
184e8e8f448e        memcached:latest                "/entrypoint.sh memca"   24 seconds ago      Up 16 seconds       11211/tcp                                      r-memcached-app-stack_memcached-service_1

Rancher官方docs中明确说明:不同Stack间service互ping,需要采用“ service_name.stack_name”的地址格式,我们在memcached-app-stack中的“r-memcached-app-stack_memcached-service_1”容器里去ping nginx-app-stack中的nginx-alpine-service服务:

$ docker exec r-memcached-app-stack_memcached-service_1  ping -c 3 nginx-alpine-service.nginx-app-stack
PING nginx-alpine-service.nginx-app-stack (10.42.164.174): 56 data bytes
64 bytes from 10.42.164.174: icmp_seq=0 ttl=62 time=0.710 ms
92 bytes from 10.42.84.96: Redirect Host
64 bytes from 10.42.164.174: icmp_seq=1 ttl=62 time=2.543 ms
--- nginx-alpine-service.nginx-app-stack ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.710/1.627/2.543/0.917 ms

ping nginx-app-stack中的redis-alpine-service服务:

$ docker exec r-memcached-app-stack_memcached-service_1  ping -c 3 redis-alpine-service.nginx-app-stack
PING redis-alpine-service.nginx-app-stack (10.42.220.43): 56 data bytes
64 bytes from 10.42.220.43: icmp_seq=0 ttl=64 time=0.161 ms
64 bytes from 10.42.220.43: icmp_seq=1 ttl=64 time=0.050 ms
64 bytes from 10.42.220.43: icmp_seq=2 ttl=64 time=0.051 ms
--- redis-alpine-service.nginx-app-stack ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.050/0.087/0.161/0.052 ms

我们通过cat /etc/resolv.conf可以查看到Rancher内部DNS的地址:

$docker exec r-memcached-app-stack_memcached-service_1  cat /etc/resolv.conf
search memcached-app-stack.rancher.internal memcached-service.memcached-app-stack.rancher.internal rancher.internal
nameserver 169.254.169.250

五、Rancher Compose CLI

Rancher除了提供UI工具外,还提供了一个名为rancher-compose的CLI工具,用于在一个stack的范围内管理各个services。rancher-compose的灵感来源于docker-compose,兼容docker-compose的配置文件格式,并有自己的扩展。此外与docker-compose不同的是rancher-compose支持跨多主机管理。

在Rancher UI的右下角有一个Rancher-compose的下载链接,支持Linux,Windows和Mac。rancher-compose当前版本是0.7.3,下载后将其路径放到PATH环境变量里,验证一下运行是否ok:

$ rancher-compose -v
rancher-compose version v0.7.3

要管理某个stack下的Service,我们至少需要提供一个docker-compose.yml文件,这里针对memcached-app-stack下的memcached-service这个服务做一些操作,我们提供一个docker-compose.yml:

memcached-service:
  log_driver: ''
  tty: true
  log_opt: {}
  image: memcached:latest
  stdin_open: true

利用dev环境的api key和secret,rancher-compose可以实现与rancher的交互:

$ rancher-compose --url http://10.10.126.101:8080  --access-key 5569108BE7489DEE47A5 --secret-key 76Yw5v63ag8SdKYQDYgVok7Co6HRncU7bUCEShXh -p memcached-app-stack up
INFO[0000] Project [memcached-app-stack]: Starting project
INFO[0000] [0/1] [memcached-service]: Starting
INFO[0000] [1/1] [memcached-service]: Started
INFO[0000] Project [memcached-app-stack]: Project started

由于memcached-service已经存在并启动了相应Container,因此上面的命令实际上没有做任何改动。如果想看rancher-compose的执行细节,可以在rancher-compose后面加上–verbose命令行option,可以看到如下结果:

$ rancher-compose --verbose --url http://10.10.126.101:8080  --access-key 5569108BE7489DEE47A5 --secret-key 76Yw5v63ag8SdKYQDYgVok7Co6HRncU7bUCEShXh -p memcached-app-stack up
DEBU[0000] Environment Context from file : map[]
DEBU[0000] Opening compose file: docker-compose.yml
DEBU[0000] [0/0] [memcached-service]: Adding
DEBU[0000] Opening rancher-compose file: /home1/tonybai/rancher-compose.yml
DEBU[0000] Looking for stack memcached-app-stack
DEBU[0000] Found stack: memcached-app-stack(1e3)
DEBU[0000] Launching action for memcached-service
DEBU[0000] Project [memcached-app-stack]: Creating project
DEBU[0000] Finding service memcached-service
DEBU[0000] [0/1] [memcached-service]: Creating
DEBU[0000] Found service memcached-service
DEBU[0000] [0/1] [memcached-service]: Created
DEBU[0000] Project [memcached-app-stack]: Project created
INFO[0000] Project [memcached-app-stack]: Starting project
DEBU[0000] Launching action for memcached-service
DEBU[0000] Finding service memcached-service
INFO[0000] [0/1] [memcached-service]: Starting
DEBU[0000] Found service memcached-service
DEBU[0000] Finding service memcached-service
INFO[0000] [1/1] [memcached-service]: Started
INFO[0000] Project [memcached-app-stack]: Project started
DEBU[0000] Found service memcached-service
DEBU[0000] Finding service memcached-service
DEBU[0000] Found service memcached-service

我们再通过rancher-compose将memcached-service扩展到两个Container:

$ rancher-compose --url http://10.10.126.101:8080  --access-key 5569108BE7489DEE47A5 --secret-key 76Yw5v63ag8SdKYQDYgVok7Co6HRncU7bUCEShXh -p memcached-app-stack scale memcached-service=2
INFO[0000] Setting scale memcached-service=2...

几秒后,Rancher UI上memcached-service的Container数量就会从1变为2。在105.72上我们也可以看到两个memcached service container:

$ docker ps
CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS              PORTS                                          NAMES
43c1443fec9f        memcached:latest                "/entrypoint.sh memca"   8 minutes ago       Up 7 minutes        11211/tcp                                      r-memcached-app-stack_memcached-service_2
184e8e8f448e        memcached:latest                "/entrypoint.sh memca"   14 hours ago        Up 13 hours         11211/tcp                                      r-memcached-app-stack_memcached-service_1

六、Service upgrade

Rancher支持stack中Service的upgrade管理。Rancher提供了两种Service Upgrade方法:In-service upgrade和Rolling upgrade(滚动升级)。rancher-compose同时支持两种升级方法,Rancher UI中针对stack下的service也有upgrade菜单选项,但UI提供的升级方式等同于in-service upgrade。

根据官方docs的说明,In-Service upgrade的默认upgrade步骤大致是:

1、停掉existing service的containers;
2、等待interval时间;
3、启动new version service的containers;
4、confirm upgrade or rollback。

而Rolling upgrade的升级步骤则是:

1、启动new service ;
2、将old service的scale降为0。

下面我们就每种method分别举一个例子说明一下(均采用rancher-compose工具)。

1、In-Service Upgrade

我们来将dev Environment下nginx-app-stack的nginx-alpine-service从nginx:1.8-alpine升级到nginx:1.9-alpine。为此我们需要给rancher-compose提供一份升级后的service的docker-compose.yml文件:

//docker-compose-nginx-service-upgrade.yml

nginx-alpine-service:
  ports:
  - 10086:80/tcp
  log_driver: ''
  labels:
    io.rancher.container.start_once: 'true'
  tty: true
  log_opt: {}
  image: nginx:1.9-alpine
  stdin_open: true

可以看到我们仅是将nginx-alpine-service的image从1.8-alpine改为1.9-alpine了。接下来我们就来升级nginx-alpine-service:

$ rancher-compose -f ./docker-compose-nginx-service-upgrade.yml --url http://10.10.126.101:8080  --access-key 5569108BE7489DEE47A5 --secret-key 76Yw5v63ag8SdKYQDYgVok7Co6HRncU7bUCEShXh -p nginx-app-stack up --upgrade nginx-alpine-service
INFO[0000] Project [nginx-app-stack]: Starting project
INFO[0000] [0/1] [nginx-alpine-service]: Starting
INFO[0000] Updating nginx-alpine-service
INFO[0001] Upgrading nginx-alpine-service
INFO[0056] [1/1] [nginx-alpine-service]: Started
INFO[0056] Project [nginx-app-stack]: Project started

我们通过Rancher UI可以看到upgrade执行在界面上体现出来的变化:

img{512x368}

Upgrade后,nginx-alpine-service的详细信息如下:

img{512x368}

我们来Confirm一下:

$ rancher-compose -f ./docker-compose-nginx-service-upgrade.yml  --url http://10.10.126.101:8080  --access-key 5569108BE7489DEE47A5 --secret-key 76Yw5v63ag8SYQDYgVok7Co6HRncU7bUCEShXh -p nginx-app-stack up --upgrade --confirm-upgrade
INFO[0000] Project [nginx-app-stack]: Starting project
INFO[0000] [0/1] [nginx-alpine-service]: Starting
INFO[0001] [1/1] [nginx-alpine-service]: Started
INFO[0001] Project [nginx-app-stack]: Project started
ERRO[0002] Failed to get logs for Default_nginx-alpine-app_1: Failed to find action: logs
ERRO[0002] Failed to get logs for nginx-app-stack_nginx-alpine-service_1: Failed to find action: logs

Confirm后,Rancher UI上的upgrade标记不见了,两个没有running的old版本 container也被cleanup了。confirm时出现两个ERRO,不知何原因,但问题不大,没有影响到confirm结果。

2、Rolling Upgrade

与In-service upgrade服务中断不同,Rolling Upgrade会先启动new Service,然后再逐渐将old service的scale减少到0。这种情况下,如果其他服务配合到位,该服务是不会中断的。

我们以nginx-app-stack中的redis-alpine-service为例,将其从redis:alpine版本升级到3.0.7-alpine。

$docker images
redis                                  3.0.7-alpine        633ba621a23f        6 weeks ago         15.95 MB
redis                                  alpine              633ba621a23f        6 weeks ago         15.95 MB
... ...

我们同样要为这次Roll upgrade准备一份docker-compose.yml文件:

//docker-compose-redis-service-upgrade.yml

redis-alpine-service:
redis-alpine-service-v1:
  log_driver: ''
  tty: true
  log_opt: {}
  image: redis:3.0.7-alpine
  stdin_open: true

执行Rolling upgrade命令:

$rancher-compose -f ./docker-compose-redis-service-upgrade.yml --url http://10.10.126.101:8080  --access-key 5569108BE7489DEE47A5 --secret-key 76Yw5v63ag8SdKYQDYgVok7Co6HRncU7bUCEShXh -p nginx-app-stack upgrade  redis-alpine-service redis-alpine-service-v1
INFO[0000] Creating service redis-alpine-service-v1
INFO[0005] Upgrading redis-alpine-service to redis-alpine-service-v1, scale=2

Rancher UI上出现如下状态变化:

img{512x368}

最终redis-alpine-service-v1启动,redis-alpine-service停止,但Rancher UI并未将其Remove,你可以手动删除,或者在上面命令中加入–cleanup自动删除old service。

七、参考资料

关于Rancher,网上可用的资料并不多,这里主要是参考了官方文档:

http://rancher.com/announcing-rancher-1-0-ga/

http://docs.rancher.com/rancher/quick-start-guide/

不过Rancher的Doc文字太多,少图,尤其是在Rancher UI介绍这块,基本无图,还待改善。

另外国内的云舒网络与 Rancher Labs是深度的合作伙伴,云舒公司博客上的内容也值得大家认真参考。

八、小结

相比于Mesos、Kubernetes和Swarm这三位欧巴,Rancher还最为年轻(至少从发布时间上来看是这样的),也刚刚起步。而这个领域的激烈的竞争也才刚刚开始。 谁能笑道最后,还待观察。

weed-fs使用简介

weed-fs,全名Seaweed-fs,是一种用golang实现的简单且高可用的分布式文件系统。该系统的目标有二:

- 存储billions of files
- serve the files fast

weed-fs起初是为了搞一个基于Fackbook的Haystack论文的实现,Haystack旨在优化Fackbook内部图片存储和获取。后在这个基 础上,weed-fs作者又增加了若干feature,形成了目前的weed-fs。

这里并不打算深入分析weed-fs源码,仅仅是从黑盒角度介绍weed-fs的使用,发掘weed-fs的功能、长处和不足。

一、weed-fs集群简介

weed-fs集群的拓扑(Topology)由DataCenter、Rack(机架)、Machine(或叫Node)组成。最初版本的weed-fs应该可以通 过配置文件来描述整个集群的拓扑结构,配置文件采用xml格式,官方给出的样例如下:

<Configuration>
  <Topology>
    <DataCenter name="dc1">
      <Rack name="rack1">
        <Ip>192.168.1.1</Ip>
      </Rack>
    </DataCenter>
    <DataCenter name="dc2">
      <Rack name="rack1">
        <Ip>192.168.1.2</Ip>
      </Rack>
      <Rack name="rack2">
        <Ip>192.168.1.3</Ip>
        <Ip>192.168.1.4</Ip>
      </Rack>
    </DataCenter>
  </Topology>
</Configuration>

但目前的版本中,该配置文件在help说明中被置为“Deprecating!”了:

$weed master -help

-conf="/etc/weedfs/weedfs.conf": Deprecating! xml configuration file

0.70版本的weed-fs在Master中维护集群拓扑,master会根据master与master、volume与master的连接 情况实时合成拓扑结构了。

weed-fs自身可以在两种模式下运行,一种是Master,另外一种则是Volume。集群的维护以及强一致性的保证由master们保 证,master间通过raft协议实现强一致性。Volume是实际管理和存储数据的运行实例。数据的可靠性则可以通过weed-fs提供的 replication机制保证。

weed-fs提供了若干种replication策略(rack – 机架,一个逻辑上的概念):

000 no replication, just one copy
001 replicate once on the same rack
010 replicate once on a different rack in the same data center
100 replicate once on a different data center
200 replicate twice on two other different data center
110 replicate once on a different rack, and once on a different data center

选择数据更可靠的策略,则会带来一些性能上的代价,这始终是一个权衡的问题。

更多的细节以及Scaling、数据迁移等方面,下面将逐一说明。

二、weed-fs集群的启动

为了实验方便,我们定义了一个weed-fs集群拓扑:

三个master:
    master1 – localhost:9333
    master2 – localhost:9334
    master3 – localhost:9335

    replication策略:100(即在另外一个不同的datacenter中复制一份)

三个volume:
         volume1 – localhost:8081  dc1
    volume2 – localhost:8082  dc1
    volume3 – localhost:8083  dc2

集群启动首先启动master们,启动顺序: master1、master2、master3:

master1:

$ weed -v=3 master -port=9333 -mdir=./m1 -peers=localhost:9333,localhost:9334,localhost:9335 -defaultReplication=100
I0820 14:37:17 07606 file_util.go:20] Folder ./m1 Permission: -rwxrwxr-x
I0820 14:37:17 07606 topology.go:86] Using default configurations.
I0820 14:37:17 07606 master_server.go:59] Volume Size Limit is 30000 MB
I0820 14:37:17 07606 master.go:69] Start Seaweed Master 0.70 beta at 0.0.0.0:9333
I0820 14:37:17 07606 raft_server.go:50] Starting RaftServer with IP:localhost:9333:
I0820 14:37:17 07606 raft_server.go:74] Joining cluster: localhost:9333,localhost:9334,localhost:9335
I0820 14:37:17 07606 raft_server.go:134] Attempting to connect to: http://localhost:9334/cluster/join
I0820 14:37:17 07606 raft_server.go:139] Post returned error:  Post http://localhost:9334/cluster/join: dial tcp 127.0.0.1:9334: connection refused
I0820 14:37:17 07606 raft_server.go:134] Attempting to connect to: http://localhost:9335/cluster/join
I0820 14:37:17 07606 raft_server.go:139] Post returned error:  Post http://localhost:9335/cluster/join: dial tcp 127.0.0.1:9335: connection refused
I0820 14:37:17 07606 raft_server.go:78] No existing server found. Starting as leader in the new cluster.
I0820 14:37:17 07606 master_server.go:93] [ localhost:9333 ] I am the leader!

I0820 14:37:52 07606 raft_server_handlers.go:16] Processing incoming join. Current Leader localhost:9333 Self localhost:9333 Peers map[]
I0820 14:37:52 07606 raft_server_handlers.go:20] Command:{"name":"localhost:9334","connectionString":"http://localhost:9334"}
I0820 14:37:52 07606 raft_server_handlers.go:27] join command from Name localhost:9334 Connection http://localhost:9334

I0820 14:38:02 07606 raft_server_handlers.go:16] Processing incoming join. Current Leader localhost:9333 Self localhost:9333 Peers map[localhost:9334:0xc20800f730]
I0820 14:38:02 07606 raft_server_handlers.go:20] Command:{"name":"localhost:9335","connectionString":"http://localhost:9335"}
I0820 14:38:02 07606 raft_server_handlers.go:27] join command from Name localhost:9335 Connection http://localhost:9335

master2:

$ weed -v=3 master -port=9334 -mdir=./m2 -peers=localhost:9333,localhost:9334,localhost:9335 -defaultReplication=100
I0820 14:37:52 07616 file_util.go:20] Folder ./m2 Permission: -rwxrwxr-x
I0820 14:37:52 07616 topology.go:86] Using default configurations.
I0820 14:37:52 07616 master_server.go:59] Volume Size Limit is 30000 MB
I0820 14:37:52 07616 master.go:69] Start Seaweed Master 0.70 beta at 0.0.0.0:9334
I0820 14:37:52 07616 raft_server.go:50] Starting RaftServer with IP:localhost:9334:
I0820 14:37:52 07616 raft_server.go:74] Joining cluster: localhost:9333,localhost:9334,localhost:9335
I0820 14:37:52 07616 raft_server.go:134] Attempting to connect to: http://localhost:9333/cluster/join
I0820 14:37:52 07616 raft_server.go:179] Post returned status:  200

master3:

$ weed -v=3 master -port=9335 -mdir=./m3 -peers=localhost:9333,localhost:9334,localhost:9335 -defaultReplication=100
I0820 14:38:02 07626 file_util.go:20] Folder ./m3 Permission: -rwxrwxr-x
I0820 14:38:02 07626 topology.go:86] Using default configurations.
I0820 14:38:02 07626 master_server.go:59] Volume Size Limit is 30000 MB
I0820 14:38:02 07626 master.go:69] Start Seaweed Master 0.70 beta at 0.0.0.0:9335
I0820 14:38:02 07626 raft_server.go:50] Starting RaftServer with IP:localhost:9335:
I0820 14:38:02 07626 raft_server.go:74] Joining cluster: localhost:9333,localhost:9334,localhost:9335
I0820 14:38:02 07626 raft_server.go:134] Attempting to connect to: http://localhost:9333/cluster/join
I0820 14:38:03 07626 raft_server.go:179] Post returned status:  200

master1启动后,发现其他两个peer master尚未启动,于是将自己选为leader。master2、master3启动后,加入到以master1为leader的 master集群。

接下来我们来启动volume servers:

volume1:

$ weed -v=3 volume -port=8081 -dir=./v1 -mserver=localhost:9333 -dataCenter=dc1
I0820 14:44:29 07642 file_util.go:20] Folder ./v1 Permission: -rwxrwxr-x
I0820 14:44:29 07642 store.go:225] Store started on dir: ./v1 with 0 volumes max 7
I0820 14:44:29 07642 volume.go:136] Start Seaweed volume server 0.70 beta at 0.0.0.0:8081
I0820 14:44:29 07642 volume_server.go:70] Volume server bootstraps with master localhost:9333
I0820 14:44:29 07642 list_masters.go:18] list masters result :{"IsLeader":true,"Leader":"localhost:9333","Peers":["localhost:9334","localhost:9335"]}
I0820 14:44:29 07642 store.go:65] current master nodes is nodes:[localhost:9334 localhost:9335 localhost:9333 localhost:9333], lastNode:3

volume server的启动大致相同,volume2和volume3的输出日志这里就不详细列出了。

volume2:

$weed -v=3 volume -port=8082 -dir=./v2 -mserver=localhost:9334 -dataCenter=dc1

volume3:

$weed -v=3 volume -port=8083 -dir=./v3 -mserver=localhost:9335 -dataCenter=dc2

三个volume server启动后,我们在leader master(9333)上能看到如下日志:

I0820 14:44:29 07606 node.go:208] topo adds child dc1
I0820 14:44:29 07606 node.go:208] topo:dc1 adds child DefaultRack
I0820 14:44:29 07606 node.go:208] topo:dc1:DefaultRack adds child 127.0.0.1:8081
I0820 14:47:09 07606 node.go:208] topo:dc1:DefaultRack adds child 127.0.0.1:8082
I0820 14:47:21 07606 node.go:208] topo adds child dc2
I0820 14:47:21 07606 node.go:208] topo:dc2 adds child DefaultRack
I0820 14:47:21 07606 node.go:208] topo:dc2:DefaultRack adds child 127.0.0.1:8083

至此,整个weed-fs集群已经启动了。初始启动后的master会在-mdir下建立一些目录和文件:

$ ls m1
conf  log  snapshot

但volume在-dir下没有做任何操作,volume server会在第一次写入数据时建立相应的.idx文件和.dat文件。

三、基本操作:存储、获取和删除文件

创建一个hello.txt文件,内容为"hello weed-fs!",用于我们测试weed-fs的基本操作。weed-fs提供了HTTP REST API接口,我们可以很方便的使用其基本功能(这里客户端使用curl)。

1、存储

我们来将hello.txt文件存储在weed-fs文件系统中,我们通过master提供的submit API接口来完成这一操作:

$ curl -F file=@hello.txt http://localhost:9333/submit
{"fid":"6,01fc4a422c","fileName":"hello.txt","fileUrl":"127.0.0.1:8082/6,01fc4a422c","size":39}

我们看到master给我们返回了一行json数据,其中:

fid是一个逗号分隔的字符串,按照repository中文档的说明,这个字符串应该由volume id, key uint64和cookie code构成。其中逗号前面的6就是volume id, 01fc4a422c则是key和cookie组成的串。fid是文件hello.txt在集群中的唯一ID。后续查看、获取以及删除该文件数据都需要使 用这个fid。

fileUrl是该文件在weed-fs中的一个访问地址(非唯一哦),这里是127.0.0.1:8082/6,01fc4a422c,可以看出weed-fs在volume server2上存储了一份hello.txt的数据。

这一存储操作引发了物理volume的创建,我们可以看到volume server的-dir下发生了变化,多了很多.idx和.dat文 件:

$ ls v1 v2 v3
v1:
3.dat  3.idx  4.dat  4.idx  5.dat  5.idx

v2:
1.dat  1.idx  2.dat  2.idx  6.dat  6.idx

v3:
1.dat  1.idx  2.dat  2.idx  3.dat  3.idx  4.dat  4.idx  5.dat  5.idx  6.dat  6.idx

并且这个创建过程是在master leader的控制之下的:

I0820 15:06:02 07606 volume_growth.go:204] Created Volume 3 on topo:dc1:DefaultRack:127.0.0.1:8081
I0820 15:06:02 07606 volume_growth.go:204] Created Volume 3 on topo:dc2:DefaultRack:127.0.0.1:8083

我们从文件的size可以看出,hello.txt文件被存储在了v2和v3下的id为6的卷(6.dat和6.idx)中:

v2:
-rw-r–r– 1 tonybai tonybai  104  8月20 15:06 6.dat
-rw-r–r– 1 tonybai tonybai   16  8月20 15:06 6.idx

v3:
-rw-r–r– 1 tonybai tonybai  104  8月20 15:06 6.dat
-rw-r–r– 1 tonybai tonybai   16  8月20 15:06 6.idx

v2和v3中的6.dat是一模一样的,6.idx也是一样的(后续在做数据迁移时,这点极其重要)。

2、获取

前面提到master给我们返回了一个fid:6,01fc4a422c以及fileUrl":"127.0.0.1:8082/6,01fc4a422c"。

通过这个fileUrl,我们可以获取到hello.txt的数据:

$ curl http://127.0.0.1:8082/6,01fc4a422c
hello weed-fs!

根据我们的replication策略,hello.txt应该还存储在v3下,我们换成8083这个volume,应该也可以得到 hello.txt数据:

$ curl http://127.0.0.1:8083/6,01fc4a422c
hello weed-fs!

如果我们通过volume1 (8081)查,应该得不到数据:

$ curl http://127.0.0.1:8081/6,01fc4a422c
<a href="http://127.0.0.1:8082/6,01fc4a422c">Moved Permanently</a>.

这里似乎是重定向了。我们给curl加上重定向处理选项再试一次:

$ curl -L  http://127.0.0.1:8081/6,01fc4a422c
hello weed-fs!

居然也能得到相应数据,从volume1的日志来看,volume1也能获取到hello.txt的正确地址,并将返回重定向请求,这样curl 就能从正确的machine上获取数据了。

如果我们通过master来获取hello.txt数据,会是什么结果呢?

$ curl -L  http://127.0.0.1:9335/6,01fc4a422c
hello weed-fs!

同样master返回重定向地址,curl从volume节点获取到正确数据。我们看看master是如何返回重定向地址的?

$ curl   http://127.0.0.1:9335/6,01fc4a422c
<a href="http://127.0.0.1:8082/6,01fc4a422c">Moved Permanently</a>.
$ curl   http://127.0.0.1:9335/6,01fc4a422c
<a href="http://127.0.0.1:8083/6,01fc4a422c">Moved Permanently</a>.

可以看到master会自动均衡负载,轮询式的返回8082和8083。0.70版本以前,通过非leader master是无法得到正确结果的,只能通过leader master得到,0.70版本fix了这个问题。

3、删除

通过fileUrl地址直接删除hello.txt:

$ curl -X DELETE http://127.0.0.1:8082/6,01fc4a422c
{"size":39}

操作成功后,我们再来get一下hello.txt:

$ curl -i  http://127.0.0.1:8082/6,01fc4a422c
HTTP/1.1 404 Not Found
Date: Thu, 20 Aug 2015 08:13:28 GMT
Content-Length: 0
Content-Type: text/plain; charset=utf-8

$ curl -i -L  http://127.0.0.1:9335/6,01fc4a422c
HTTP/1.1 301 Moved Permanently
Content-Length: 69
Content-Type: text/html; charset=utf-8
Date: Thu, 20 Aug 2015 08:13:56 GMT
Location: http://127.0.0.1:8082/6,01fc4a422c

HTTP/1.1 404 Not Found
Date: Thu, 20 Aug 2015 08:13:56 GMT
Content-Length: 0
Content-Type: text/plain; charset=utf-8

可以看出,无论是直接通过volume还是间接通过master都无法获取到hello.txt了,hello.txt被成功删除了。

不过删除hello.txt后,volume server下的数据文件的size却并没有随之减小,别担心,这就是weed-fs的处理方法,这些数据删除后遗留下来的空洞需要手工清除(对数据文件 进行手工紧缩):

$ curl "http://localhost:9335/vol/vacuum"
{"Topology":{"DataCenters":[{"Free":8,"Id":"dc1","Max":14,"Racks":[{"DataNodes":[{"Free":4,"Max":7,"PublicUrl":"127.0.0.1:8081","Url":"127.0.0.1:8081","Volumes":3},{"Free":4,"Max":7,"PublicUrl":"127.0.0.1:8082","Url":"127.0.0.1:8082","Volumes":3}],”Free”:8,”Id”:”DefaultRack”,”Max”:14}]},{“Free”:1,”Id”:”dc2″,”Max”:7,”Racks”:[{"DataNodes":[{"Free":1,"Max":7,"PublicUrl":"127.0.0.1:8083","Url":"127.0.0.1:8083","Volumes":6}],”Free”:1,”Id”:”DefaultRack”,”Max”:7}]}],”Free”:9,”Max”:21,”layouts”:[{"collection":"","replication":"100","ttl":"","writables":[1,2,3,4,5,6]}]},"Version":"0.70 beta"}

紧缩后,你再查看v1, v2, v3下的文件size,真的变小了。

四、一致性(consistency)

在分布式系统中,“一致性”是永恒的难题。weed-fs支持replication,其多副本的数据一致性需要保证。

weed-fs理论上采用了是一种“强一致性”的策略,即:

存储文件时,当多个副本都存储成功后,才会返回成功;任何一个副本存储失败,此次存储操作则返回失败。
删除文件时,当所有副本都删除成功后,才返回成功;任何一个副本删除失败,则此次删除操作返回失败。

我们来验证一下weed-fs是否做到了以上两点:

1、存储的一致性保证

我们先将volume3停掉(即dc2),这样在replication 策略为100时,向weed-fs存储hello.txt时会发生如下结果:

$ curl -F file=@hello.txt http://localhost:9333/submit
{"error":"Cannot grow volume group! Not enough data node found!"}

master根据100策略,需要在dc2选择一个volume存储hello.txt的副本,但dc2所有machine都down掉了,因此 没有存储空间,于是master认为此次操作无法继续进行,返回失败。这点符合存储一致性的要求。

2、删除的一致性保证

恢复dc2,将hello.txt存入:

$ curl -F file=@hello.txt http://localhost:9333/submit
{"fid":"6,04dce94a72","fileName":"hello.txt","fileUrl":"127.0.0.1:8082/6,04dce94a72","size":39}

再次停掉dc2,之后尝试删除hello.txt(通过master删除):

$ curl -L  -X DELETE http://127.0.0.1:9333/6,04dce94a72
{"error":"Deletion Failed."}

虽然返回的是delete failed,但从8082上的日志来看,似乎8082已经将hello.txt删除了:

I0820 17:32:20 07653 volume_server_handlers_write.go:53] deleting Cookie:3706276466, Id:4, Size:0, DataSize:0, Name: , Mime:

我们再从8082获取一下hello.txt:

$ curl  http://127.0.0.1:8082/6,04dce94a72

结果是什么也没有返回。

从8082日志来看:

I0820 17:33:24 07653 volume_server_handlers_read.go:53] read error: File Entry Not Found. Needle 70 Memory 0 /6,04dce94a72

hello.txt的确被删除了!

这时将dc2(8083)重新启动!我们尝试从8083获取hello.txt:

$ curl  http://127.0.0.1:8083/6,04dce94a72
hello weed-fs!

8083上的hello.txt依旧存在,可以被读取。

再试试通过master来获取hello.txt:

$ curl  -L http://127.0.0.1:9333/6,04dce94a72
$ curl  -L http://127.0.0.1:9333/6,04dce94a72
hello weed-fs!

结果是有时能返回hello.txt内容,有时不行。显然这是与master的自动负载均衡有关,返回8082这个重定向地址,则curl无法得 到结果;但若返回8083这个重定向地址,我们就可以得到hello.txt的内容。

这样来看,目前weed-fs的删除操作还无法保证强一致性。weed-fs github.com上已有若干issues(#172,#179,#182)是关于这个问题的。在大数据量(TB、PB级别)的情况下,这种不一致性最 大的问题是导致storage leak,即空间被占用而无法回收,volume将被逐个逐渐占满,期待后续的解决方案吧。

五、目录支持

weed-fs还支持像传统文件系统那样,将文件放在目录下管理,并通过文件路径对文件进行存储、获取和删除操作。weed-fs对目录的支持是 通过另外一个server实现的:filer server。也就是说如果想拥有对目录的支持,则必须启动一个(或若干个) filer server,并且所有的操作都要通过filer server进行。

$ weed filer -port=8888 -dir=./f1 -master=localhost:9333 -defaultReplicaPlacement=100
I0820 22:09:40 08238 file_util.go:20] Folder ./f1 Permission: -rwxrwxr-x
I0820 22:09:40 08238 filer.go:88] Start Seaweed Filer 0.70 beta at port 8888

1、存储

$curl -F "filename=@hello.txt" "http://localhost:8888/foo/"
{"name":"hello.txt","size":39}

2、获取

$ curl http://localhost:8888/foo/hello.txt
hello weed-fs!

3、查询目录文件列表

$ curl "http://localhost:8888/foo/?pretty=y"
{
  "Directory": "/foo/",
  "Files": [
    {
      "name": "hello.txt",
      "fid": "6,067281a126"
    }
  ],
  "Subdirectories": null
}

4、删除

$ curl -X DELETE http://localhost:8888/foo/hello.txt
{"error":""}

再尝试获取hello.txt:

$curl http://localhost:8888/foo/hello.txt
返回空。hello.txt已被删除。

5、filer server

weed filer server是单点,我们再来启动一个filer server。

$ weed filer -port=8889 -dir=./f2 -master=localhost:9333 -defaultReplicaPlacement=100
I0821 13:47:52 08973 file_util.go:20] Folder ./f2 Permission: -rwxrwxr-x
I0821 13:47:52 08973 filer.go:88] Start Seaweed Filer 0.70 beta at port 8889

两个filer节点间是否有协调呢?我们来测试一下:我们从8888存储一个文件,然后从8889获取这个文件:

$ curl -F "filename=@hello.txt" "http://localhost:8888/foo/"
{"name":"hello.txt","size":39}
$ curl http://localhost:8888/foo/hello.txt
hello weed-fs!
$ curl http://localhost:8889/foo/hello.txt

从测试结果来看,二者各自独立工作,并没有任何联系,也就是说没有共享“文件full path”到"fid"的索引关系。默认情况下 filer server都是工作在standalone模式下的。

weed-fs官方给出了filer的集群方案,即使用redis或Cassandra作为后端,在多个filer节点间共享“文件full path”到"fid"的索引关系。

我们启动一个redis-server(2.8.21),监听在默认的6379端口。用下面命令重启两个filer server节点:

$ weed filer -port=8888 -dir=./f1 -master=localhost:9333 -defaultReplicaPlacement=100 -redis.server=localhost:6379
$ weed filer -port=8889 -dir=./f2 -master=localhost:9333 -defaultReplicaPlacement=100 -redis.server=localhost:6379

重复一下上面的测试步骤:
$ curl -F "filename=@hello.txt" "http://localhost:8888/foo/"
{"name":"hello.txt","size":39}

$ curl http://localhost:8889/foo/hello.txt
hello weed-fs!

可以看到从8888存储的文件,可以被从8889获取到。

我们删除这个文件:
$ curl -X DELETE http://localhost:8889/foo/hello.txt
{"error":"Invalid fileId "}

提示error,但实际上文件已经被删除了!这块可能是个小bug(#183)。

虽然filer是集群了,但其后端的redis依旧是单点,如果考虑高可靠性,redis显然也要做好集群。

六、Collection

Collection,顾名思义是“集合”,在weed-fs中,它指的是物理volume的集合。前面我们在存储文件时并没有指定 collection,因此weed-fs采用默认collection(空)。如果我们指定集合,结果会是什么样子呢?

$ curl -F file=@hello.txt "http://localhost:9333/submit?collection=picture"
{"fid":"7,0c4f5dc90f","fileName":"hello.txt","fileUrl":"127.0.0.1:8083/7,0c4f5dc90f","size":39}

$ ls v1 v2 v3
v1:
3.dat  3.idx  4.dat  4.idx  5.dat  5.idx  picture_7.dat  picture_7.idx
v2:
1.dat  1.idx  2.dat  2.idx  6.dat  6.idx
v3:
1.dat  1.idx  2.dat  2.idx  3.dat  3.idx  4.dat  4.idx  5.dat  5.idx  6.dat  6.idx  picture_7.dat  picture_7.idx

可以看出volume server在自己的-dir下面建立了一个collection名字为prefix的idx和dat文件,上述例子中hello.txt被分配到 8081和8083两个volume server上,因此这两个volume server各自建立了picture_7.dat和picture_7.idx。以picture为前缀的idx和dat文件只是用来存放存储在 collection=picture的文件数据,其他数据要么存储在默认collection中,要么存储在其他名字的collection 中。

collection就好比为Windows下位驱动器存储卷起名。比如C:叫"系统盘",D叫“程序盘”,E叫“数据盘”。这里各个 volume server下的picture_7.dat和picture_7.idx被起名为picture卷。如果还有video collection,那么它可能由各个volume server下的video_8.dat和video_8.idx。

不过由于默认情况下,weed volume的默认-max="7",因此在实验环境下每个volume server最多在-dir下建立7个物理卷(七对.idx和.dat)。如果此时我还想建立video卷会怎么样呢?

$ curl -F file=@hello.txt "http://localhost:9333/submit?collection=video"
{"error":"Cannot grow volume group! Not enough data node found!"}

volume server们返回失败结果,提示无法再扩展volume了。这时你需要重启各个volume server,将-max值改大,比如100。

比如:$weed -v=3 volume -port=8083 -dir=./v3 -mserver=localhost:9335 -dataCenter=dc2 -max=100

重启后,我们再来建立video collection:

$ curl -F file=@hello.txt "http://localhost:9333/submit?collection=video"
{"fid":"11,0ee98ca54d","fileName":"hello.txt","fileUrl":"127.0.0.1:8083/11,0ee98ca54d","size":39}

$ ls v1 v2 v3
v1:
3.dat  4.dat  5.dat  picture_7.dat  video_10.dat  video_11.dat  video_12.dat  video_13.dat  video_9.dat
3.idx  4.idx  5.idx  picture_7.idx  video_10.idx  video_11.idx  video_12.idx  video_13.idx  video_9.idx

v2:
1.dat  1.idx  2.dat  2.idx  6.dat  6.idx  video_8.dat  video_8.idx

v3:
1.dat  2.dat  3.dat  4.dat  5.dat  6.dat  picture_7.dat  video_10.dat  video_11.dat  video_12.dat  video_13.dat  video_8.dat  video_9.dat
1.idx  2.idx  3.idx  4.idx  5.idx  6.idx  picture_7.idx  video_10.idx  video_11.idx  video_12.idx  video_13.idx  video_8.idx  video_9.idx

可以看到每个datacenter的volume server一次分配了6个volume作为video collection的存储卷。

七、伸缩(Scaling)

对于分布式系统来说,Scaling是不得不考虑的问题,也是极为常见的操作。

1、伸(scale up)

weed-fs对“伸"的支持是很好的,我们分角色说。

【master】
    master间采用的是raft协议,增加一个master,对于集群来说是最最基本的操作:

$weed -v=3 master -port=9336 -mdir=./m4 -peers=localhost:9333,localhost:9334,localhost:9335,localhost:9336 -defaultReplication=100
I0821 15:45:47 12398 file_util.go:20] Folder ./m4 Permission: -rwxrwxr-x
I0821 15:45:47 12398 topology.go:86] Using default configurations.
I0821 15:45:47 12398 master_server.go:59] Volume Size Limit is 30000 MB
I0821 15:45:47 12398 master.go:69] Start Seaweed Master 0.70 beta at 0.0.0.0:9336
I0821 15:45:47 12398 raft_server.go:50] Starting RaftServer with IP:localhost:9336:
I0821 15:45:47 12398 raft_server.go:74] Joining cluster: localhost:9333,localhost:9334,localhost:9335,localhost:9336
I0821 15:45:48 12398 raft_server.go:134] Attempting to connect to: http://localhost:9333/cluster/join
I0821 15:45:49 12398 raft_server.go:179] Post returned status:  200

新master节点启动后,会通过raft协议自动加入到以9333为leader的master集群中。

【volume】

和master一样,volume本身就是靠master管理的,volume server之间没有什么联系,增加一个volume server要做的就是启动一个新的volume server就好了:

$ weed -v=3 volume -port=8084 -dir=./v4 -mserver=localhost:9335 -dataCenter=dc2
I0821 15:48:21 12412 file_util.go:20] Folder ./v4 Permission: -rwxrwxr-x
I0821 15:48:21 12412 store.go:225] Store started on dir: ./v4 with 0 volumes max 7
I0821 15:48:21 12412 volume.go:136] Start Seaweed volume server 0.70 beta at 0.0.0.0:8084
I0821 15:48:21 12412 volume_server.go:70] Volume server bootstraps with master localhost:9335
I0821 15:48:22 12412 list_masters.go:18] list masters result :
I0821 15:48:22 12412 list_masters.go:18] list masters result :{"IsLeader":true,"Leader":"localhost:9333","Peers":["localhost:9334","localhost:9335","localhost:9336"]}
I0821 15:48:22 12412 store.go:65] current master nodes is nodes:[localhost:9334 localhost:9335 localhost:9336 localhost:9333 localhost:9333], lastNode:4
I0821 15:48:22 12412 volume_server.go:82] Volume Server Connected with master at localhost:9333

新volume server节点启动后,同样会自动加入集群,后续master就会自动在其上存储数据了。

【filer】

前面已经谈到了,无论是standalone模式,还是distributed模式,filter都可以随意增减,这里就不再重复赘述了。

2、缩(scale down)

master的缩是极其简单的,只需将相应节点shutdown即可;如果master是leader,则其他master会检测到leader shutdown,并自动重新选出新leader。不过在leader选举的过程中,整个集群的服务将短暂停止,直到leader选出。

filer在standalone模式下,谈伸缩是毫无意义的;对于distributed模式下,filter节点和master节点缩的方法 一致,shutdown即可。

唯一的麻烦就是volume节点,因为数据存储在volume节点下,我们不能简单的停掉volume,我们需要考虑在不同 replication策略下是否可以做数据迁移,如何做数据迁移。这就是下一节我们要详细描述的。

八、数据迁移

下面我们就来探讨一下weed-fs的volume数据迁移问题。

1、000复制策略下的数据迁移

为方便测试,我简化一下实验环境(一个master+3个volume):

master:

$ weed -v=3 master -port=9333 -mdir=./m1 -defaultReplication=000

volume:

$ weed -v=3 volume -port=8081 -dir=./v1 -mserver=localhost:9333 -dataCenter=dc1
$ weed -v=3 volume -port=8082 -dir=./v2 -mserver=localhost:9333 -dataCenter=dc1
$ weed -v=3 volume -port=8083 -dir=./v3 -mserver=localhost:9333 -dataCenter=dc1

和之前一样,启动后,v1,v2,v3目录下面是空的,卷的创建要等到第一份数据存入时。000策略就是没有副本的策略,你存储的文件在 weed-fs中只有一份数据。

我们上传一份文件:

$ curl -F filename=@hello1.txt "http://localhost:9333/submit"
{"fid":"1,01655ab58e","fileName":"hello1.txt","fileUrl":"127.0.0.1:8081/1,01655ab58e","size":40}

$ ll v1 v2 v3

v1:
-rw-r–r– 1 tonybai tonybai  104  8 21 21:31 1.dat
-rw-r–r– 1 tonybai tonybai   16  8 21 21:31 1.idx
-rw-r–r– 1 tonybai tonybai    8  8 21 21:31 4.dat
-rw-r–r– 1 tonybai tonybai    0  8 21 21:31 4.idx
-rw-r–r– 1 tonybai tonybai    8  8 21 21:31 7.dat
-rw-r–r– 1 tonybai tonybai    0  8 21 21:31 7.idx

v2:
-rw-r–r– 1 tonybai tonybai    8  8 21 21:31 2.dat
-rw-r–r– 1 tonybai tonybai    0  8 21 21:31 2.idx
-rw-r–r– 1 tonybai tonybai    8  8 21 21:31 3.dat
-rw-r–r– 1 tonybai tonybai    0  8 21 21:31 3.idx
-rw-r–r– 1 tonybai tonybai    8  8 21 21:31 6.dat
-rw-r–r– 1 tonybai tonybai    0  8 21 21:31 6.idx

v3:
-rw-r–r– 1 tonybai tonybai    8  8 21 21:31 5.dat
-rw-r–r– 1 tonybai tonybai    0  8 21 21:31 5.idx

可以看到hello1.txt被存储在v1下,同时可以看出不同的物理卷分别存放在不同节点下(由于不需要do replication)。

在这种情况(000)下,如果要将v1数据迁移到v2或v3中,只需将v1停掉,将v1下的文件mv到v2或v3中,重启volume server2或volume server3即可。

2、001复制策略下的数据迁移

001复制策略是weed-fs默认的复制策略,weed-fs会为每个文件在同Rack下复制一个副本。我们还利用上面的环境,不过需要停掉 weed-fs,清空目录下的文件,重启后使用,别忘了-defaultReplication=001。

我们连续存储三个文件:

$ curl -F filename=@hello1.txt "http://localhost:9333/submit"
{"fid":"2,01ea84980d","fileName":"hello1.txt","fileUrl":"127.0.0.1:8082/2,01ea84980d","size":40}

$ curl -F filename=@hello2.txt "http://localhost:9333/submit"
{"fid":"1,027883baa8","fileName":"hello2.txt","fileUrl":"127.0.0.1:8083/1,027883baa8","size":40}

$ curl -F filename=@hello3.txt "http://localhost:9333/submit"
{"fid":"6,03220f577e","fileName":"hello3.txt","fileUrl":"127.0.0.1:8081/6,03220f577e","size":40}

可以看出三个文件分别被存储在vol2, vol1和vol6中,我们查看一下v1, v2, v3中的文件情况:

$ ll v1 v2 v3
v1:
-rw-r–r– 1 tonybai tonybai  104  8 21 22:00 1.dat
-rw-r–r– 1 tonybai tonybai   16  8 21 22:00 1.idx
-rw-r–r– 1 tonybai tonybai    8  8 21 21:56 3.dat
-rw-r–r– 1 tonybai tonybai    0  8 21 21:56 3.idx
-rw-r–r– 1 tonybai tonybai    8  8 21 21:56 4.dat
-rw-r–r– 1 tonybai tonybai    0  8 21 21:56 4.idx
-rw-r–r– 1 tonybai tonybai  104  8 21 22:02 6.dat
-rw-r–r– 1 tonybai tonybai   16  8 21 22:02 6.idx

v2:
-rw-r–r– 1 tonybai tonybai  104  8 21 21:56 2.dat
-rw-r–r– 1 tonybai tonybai   16  8 21 21:56 2.idx
-rw-r–r– 1 tonybai tonybai    8  8 21 21:56 5.dat
-rw-r–r– 1 tonybai tonybai    0  8 21 21:56 5.idx

v3:
-rw-r–r– 1 tonybai tonybai  104  8 21 22:00 1.dat
-rw-r–r– 1 tonybai tonybai   16  8 21 22:00 1.idx
-rw-r–r– 1 tonybai tonybai  104  8 21 21:56 2.dat
-rw-r–r– 1 tonybai tonybai   16  8 21 21:56 2.idx
-rw-r–r– 1 tonybai tonybai    8  8 21 21:56 3.dat
-rw-r–r– 1 tonybai tonybai    0  8 21 21:56 3.idx
-rw-r–r– 1 tonybai tonybai    8  8 21 21:56 4.dat
-rw-r–r– 1 tonybai tonybai    0  8 21 21:56 4.idx
-rw-r–r– 1 tonybai tonybai    8  8 21 21:56 5.dat
-rw-r–r– 1 tonybai tonybai    0  8 21 21:56 5.idx
-rw-r–r– 1 tonybai tonybai  104  8 21 22:02 6.dat
-rw-r–r– 1 tonybai tonybai   16  8 21 22:02 6.idx

假设我们现在要shutdown v3,将v3数据迁移到其他volume server,我们有3种做法:

1) 不迁移
2) 将v3下的所有文件mv到v2或v1中
3) 将v3下的所有文件先后覆盖到v1和v2中

我们来逐个分析每种做法的后果:

1)  不迁移

001策略下,每份数据有两个copy,v3中的数据其他两个v1+v2总是有的,因此即便不迁移,v1+v2中也会有一份数据copy。你可以 测试一下当shutdown volume3后:

$ curl -L "http://localhost:9333/2,01ea84980d"
hello weed-fs1!
$ curl -L "http://localhost:9333/1,027883baa8"
hello weed-fs2!
$ curl -L "http://localhost:9333/6,03220f577e"
hello weed-fs3!

针对每一份文件,你都可以多get几次,都会得到正确的结果。但此时的不足也很明显,那就是存量数据不再拥有另外一份备份。

2) 将v3下的所有文件mv到v2或v1中

还是根据001策略,将v3数据mv到v2或v1中,结果会是什么呢,这里就以v3 mv到 v1举例:
 
 - 对于v1和v3都有的卷id,比如1,两者的文件1.idx和1.dat是一模一样的。这是001策略决定的。但一旦迁移后,系统中的数据就由2份变 成1份了
 - 对于v1有,而v3没有的,那自然不必说了。
 - 对于v1没有,而v3有的,mv过去就成为了v1的数据。

为此,这种做法依旧不够完美。

3)将v3下的所有文件覆盖到v1和v2中

结合上面的方法,只有此种迁移方式才能保证迁移后,系统中的数据不丢失,且每个都是按照001策略所说的2份,这才是正确的方法。

我们来测试一下:

   – 停掉volume3;
   – 停掉volume1,将v3下的文件copy到v1下,启动volume1
   – 停掉volume2,将v3下的文件copy到v2下,启动volume2

$ curl  "http://localhost:9333/6,03220f577e"
<a href="http://127.0.0.1:8081/6,03220f577e">Moved Permanently</a>.

$ curl  "http://localhost:9333/6,03220f577e"
<a href="http://127.0.0.1:8082/6,03220f577e">Moved Permanently</a>.

可以看到,master返回了重定向地址8081和8082,说明8083迁移到8082上的数据也生效了。

3、100复制策略下的数据迁移

测试环境稍作变化:

master:

$ weed -v=3 master -port=9333 -mdir=./m1 -defaultReplication=100

volume:

$ weed -v=3 volume -port=8081 -dir=./v1 -mserver=localhost:9333 -dataCenter=dc1
$ weed -v=3 volume -port=8082 -dir=./v2 -mserver=localhost:9333 -dataCenter=dc1
$ weed -v=3 volume -port=8083 -dir=./v3 -mserver=localhost:9333 -dataCenter=dc2

和之前一样,我们上传三份文件:

$ curl -F filename=@hello1.txt "http://localhost:9333/submit"
{"fid":"4,01d937dd30","fileName":"hello1.txt","fileUrl":"127.0.0.1:8083/4,01d937dd30","size":40}

$ curl -F filename=@hello2.txt "http://localhost:9333/submit"
{"fid":"2,025efbef14","fileName":"hello2.txt","fileUrl":"127.0.0.1:8082/2,025efbef14","size":40}

$ curl -F filename=@hello3.txt "http://localhost:9333/submit"
{"fid":"2,03be936488","fileName":"hello3.txt","fileUrl":"127.0.0.1:8082/2,03be936488","size":40}

$ ll v1 v2 v3
-rw-r–r– 1 tonybai tonybai    8  8 21 22:58 3.dat
-rw-r–r– 1 tonybai tonybai    0  8 21 22:58 3.idx
-rw-r–r– 1 tonybai tonybai  104  8 21 22:58 4.dat
-rw-r–r– 1 tonybai tonybai   16  8 21 22:58 4.idx

v2:
-rw-r–r– 1 tonybai tonybai    8  8 21 22:58 1.dat
-rw-r–r– 1 tonybai tonybai    0  8 21 22:58 1.idx
-rw-r–r– 1 tonybai tonybai  200  8 21 22:59 2.dat
-rw-r–r– 1 tonybai tonybai   32  8 21 22:59 2.idx
-rw-r–r– 1 tonybai tonybai    8  8 21 22:58 5.dat
-rw-r–r– 1 tonybai tonybai    0  8 21 22:58 5.idx
-rw-r–r– 1 tonybai tonybai    8  8 21 22:58 6.dat
-rw-r–r– 1 tonybai tonybai    0  8 21 22:58 6.idx

v3:
-rw-r–r– 1 tonybai tonybai    8  8 21 22:58 1.dat
-rw-r–r– 1 tonybai tonybai    0  8 21 22:58 1.idx
-rw-r–r– 1 tonybai tonybai  200  8 21 22:59 2.dat
-rw-r–r– 1 tonybai tonybai   32  8 21 22:59 2.idx
-rw-r–r– 1 tonybai tonybai    8  8 21 22:58 3.dat
-rw-r–r– 1 tonybai tonybai    0  8 21 22:58 3.idx
-rw-r–r– 1 tonybai tonybai  104  8 21 22:58 4.dat
-rw-r–r– 1 tonybai tonybai   16  8 21 22:58 4.idx
-rw-r–r– 1 tonybai tonybai    8  8 21 22:58 5.dat
-rw-r–r– 1 tonybai tonybai    0  8 21 22:58 5.idx
-rw-r–r– 1 tonybai tonybai    8  8 21 22:58 6.dat
-rw-r–r– 1 tonybai tonybai    0  8 21 22:58 6.idx

由于100策略是在不同DataCenter中各保持一份copy,因此数据的迁移不应该在数据中心间进行,而同一数据中心内的迁移又回归到了 “000”策略的情形。

其他策略的分析方式也是如此,这里就不长篇大论了。

九、Benchmark

在HP ProLiant DL380 G4, Intel(R) Xeon(TM) CPU 3.60GHz 4核,6G内存的机器(非SSD硬盘)上,执行benchmark test:

$ weed benchmark -server=localhost:9333

This is SeaweedFS version 0.70 beta linux amd64

———— Writing Benchmark ———-
Concurrency Level:      16
Time taken for tests:   831.583 seconds
Complete requests:      1048576
Failed requests:        0
Total transferred:      1106794545 bytes
Requests per second:    1260.94 [#/sec]
Transfer rate:          1299.75 [Kbytes/sec]

Connection Times (ms)
              min      avg        max      std
Total:        2.2      12.5       1118.4      9.3

Percentage of the requests served within a certain time (ms)
   50%     11.4 ms
   66%     13.3 ms
   75%     14.8 ms
   80%     15.9 ms
   90%     19.2 ms
   95%     22.6 ms
   98%     27.4 ms
   99%     31.2 ms
  100%    1118.4 ms

———— Randomly Reading Benchmark ———-
Concurrency Level:      16
Time taken for tests:   151.480 seconds
Complete requests:      1048576
Failed requests:        0
Total transferred:      1106791113 bytes
Requests per second:    6922.22 [#/sec]
Transfer rate:          7135.28 [Kbytes/sec]

Connection Times (ms)
              min      avg        max      std
Total:        0.1      2.2       116.7      3.9

Percentage of the requests served within a certain time (ms)
   50%      1.6 ms
   66%      2.1 ms
   75%      2.5 ms
   80%      2.8 ms
   90%      3.7 ms
   95%      4.8 ms
   98%      7.4 ms
   99%     11.1 ms
  100%    116.7 ms

这个似乎比作者在mac笔记本(SSD)上性能还要差些,当然此次我们用的策略是100,并且这个服务器上还运行着其他程序。但即便如此,感觉weed-fs还是有较大优化的空间的。

作者在官网上将weed-fs与其他分布式文件系统如Ceph,hdfs等做了简要对比,强调了weed-fs相对于其他分布式文件系统的优点。

十、其它

weed-fs使用google glog,因此所有log的级别设置以及log定向的方法均与glog一致。

weed-fs提供了backup命令,用来在同机上备份volume server上的数据。

weed-fs没有提供官方client包,但在wiki上列出多种第三方client包(各种语言),就Go client包来看,似乎还没有特别理想的。

weed-fs目前还没有web console,只能通过命令行进行操作。

使用weed-fs时,别忘了将open files no limit调大,否则可能会导致volume server crash。

十一、小结

weed-fs为想寻找开源分布式文件系统的朋友们提供了一个新选择。尤其是在存储大量小图片时,weed-fs自身就是基于haystack这一优化图 片存储的论文的。另外weed-fs使用起来的确十分简单,分分钟就可以建立起一个分布式系统,部署容易,几乎不需要什么配置。但weed-fs目前最大 的问题似乎是没有重量级的使用案例,自身也还有不少不足,但希望通过这篇文章能让更多人认识weed-fs,并使用weed-fs,帮助改善weed-fs吧。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats