Docker 1.12 Swarm Mode集群实战(第三章)

在第一章 (Docker 1.12 Swarm Mode集群实战(第一章))和过渡篇中 (Docker 1.12 Swarm Mode集群实战(过渡篇)之Registry和Image) 我们理解了在Swarm上运行Docker币应用的背景和瓶颈,并且将集群环境中私有RegistryImage准备完毕。本章内容将正式部署Docker币应用到Docker原生Swarm集群并做更加深入的应用瓶颈分析。

3.1 Overlay网络

为了让我们的应用跑在swram集群上,我们要解决容器间的网络通信问题。单节点场景中,我们应用所有的容器都跑在一台主机上, 所以容器之间的网络是内部互通的。

现在我们的集群有5台主机, 需要将docker币的服务会分布式部署在这5台主机上,这就涉及到容器跨主机的网络通信了。

那我们该如何保证不同主机上的容器网络互通呢?
不用担心,swarm集群已经帮我们解决了这个问题了,那就是overlay network.

在docker 1.12以前, swarm集群需要一个额外的key-value存储(consul, etcd etc)来同步网络配置, 保证所有容器在同一个网段中。

在docker 1.12中已经内置了这个存储并且集成了overlay networks的支持。至于overlay network的细节, 就不多介绍了。

下面我们演示下如何创建一个overlay network:
只需要使用docker network create这样一个简单的命令.

# 为我们的docker币应用创建一个名为dockercoins的overlay network
# docker network create --driver overlay dockercoins
396fwpd5ja6azh93dshalmxro

# 查询docker network 列表
# docker network ls
NETWORK ID NAME DRIVER SCOPE
...
396fwpd5ja6a dockercoins overlay swarm
5929cc7b1912 host host local
6yiheh8d2itd ingress overlay swarm
...

在网络列表中你可以看到dockercoins网络的SCOPE是swarm, 表示该网络是在整个swarm集群生效的, 其他一些网络是local, 表示本机网络.

你只需要在manager节点创建overlay network即可, Swarm集群会自动配置到其他的节点。当overlay network在manager节点创建完毕后再查看其他节点的网络状态,可以看到各节点的dockercoins网络都已经创建了.:
# ssh node03 docker network ls

3.1.1 在网络上运行容器

现在我们有了dockercoins网络了, 怎么指定容器或者服务运行在哪个网络上呢?

下面我们可以先启动一个redis服务, redis服务为我们docker币应用的数据库。如果你还记得我们的应用架构,worker服务会把计算到的docker币保存到redis数据库中, webui会从redis中读取docker币的数量。
不记得, 请回顾第一章, 嘿嘿…

直接使用--network <network name>参数, 在指定网络上创建service.
# docker service create --network dockercoins --name redis redis
1lqi13cteor9qj5ihv40eo43i

# docker service ls
ID NAME REPLICAS IMAGE COMMAND
1lqi13cteor9 redis 1/1 redis

3.2 Swarm集群上运行docker币应用

redis服务已创建好了, 下面我们可以使用之前push到本地镜像仓库的镜像启动hasher, rng, webui, worker服务。

以hasher为例:

# docker service create --network dockercoins --name hasher localhost:5000/dockercoins_hasher:v0.1
9jtetr0glu6uudzy72bywgrgf

注意, 我们启动的镜像名字为localhost:5000/dockercoins_hasher:v0.1。当主机上没有这个镜像时, 会自动到本地镜像仓库拉取镜像.

下面的这段脚本可以帮我们启动所有的服务, 你可以直接粘贴到命令行执行:

DOCKER_REGISTRY=localhost:5000
TAG=v0.1
for SERVICE in hasher rng webui worker; do
docker service create --network dockercoins --name $SERVICE \
$DOCKER_REGISTRY/dockercoins_$SERVICE:$TAG
done

完成后检查我们service的启动情况:

# docker service ls
ID NAME REPLICAS IMAGE COMMAND
1lqi13cteor9 redis 1/1 redis
9jtetr0glu6u hasher 1/1 localhost:5000/dockercoins_hasher:v0.1
akxrlmck4u0r webui 1/1 localhost:5000/dockercoins_webui:v0.1
d7g0estex65u worker 1/1 localhost:5000/dockercoins_worker:v0.1
eqicwcgv877q registry 1/1 registry:2
ey7oe8o40471 rng 1/1 localhost:5000/dockercoins_rng:v0.1

好了下面我们可以开心的继续挖docker币了, 打开webui先.
Oops~, 我们忘记发布webui的端口了, 所以我们没法访问webui.。因为没法动态的修改servcie端口发布, 所以我们只能删除webui服务,重新建一个了.

# docker service ls
ID NAME REPLICAS IMAGE COMMAND
...
akxrlmck4u0r webui 1/1 localhost:5000/dockercoins_webui:v0.1
...
# docker service rm webui
webui
# docker service create --network dockerconins --name webui --publish 8000:80 localhost:5000/dockercoins_webui:v0.1
cvr2cwm7lqzezxeztljn7zgyr

好了, 现在你可以用浏览器访问http://192.168.33.101:8000/index.html 就能看到我们熟悉的webui了.
事实上, 你可以通过访问swarm集群中的所有节点(192.168.33.102 – 192.168.33.105)的8000端口来访问到我们的webui.

3.3 扩展(Scaling)应用

好了,现在万事具备, 回到我们第一章结尾的问题, 这个坑有点长~~~ 嘿嘿.

在第一章结尾, 我们分析了docker币应用的瓶颈, 在单台服务器的情况下, 我们scale up worker节点到10个副本的时候. 产生的docker币数量并没有按照预想的情况增加.

我们找到了两个瓶颈:

  • 单台服务器性能的瓶颈.
  • rng 服务的瓶颈.

其实主要是rng服务的瓶颈啦, 为了解决这个性能问题, 我们才引入docker swarm集群.
打开webui后, 可以看到我们只有一个worker副本, 每秒产生约4个docker币.

那么,增加worker容器到10个

# docker service scale worker=10
worker scaled to 10

# docker service ls
ID NAME REPLICAS IMAGE COMMAND
...
d7g0estex65u worker 8/10 localhost:5000/dockercoins_worker:v0.1
...

此时瓶颈再次出现了, 查看webui可以发现每秒产生约10个docker币,但是理论值是40。

前面我们已经分析过瓶颈出现在rng服务, 下面我们就来扩展rng服务.
当然我们可以同样使用docker service scale命令, 跟上面扩展worker服务一样增加rng服务的容器。

不过这次我们换一种方式玩,这次我们通过修改rng服务的属性实现.
使用如下命令查询service属性:

# docker service inspect rng
...
"Mode": {
"Replicated": {
"Replicas": 1
}
},
...

更新rng服务属性:

# docker service update rng --replicas 5
rng

# docker service ls
ID NAME REPLICAS IMAGE COMMAND
...
ey7oe8o40471 rng 5/5 localhost:5000/dockercoins_rng:v0.1

再回到webui, 这时可以看到每秒可以产生约30个docker币了。不过这离我们的理论值10个worker每秒产生40个docker币还是差一点.

3.4 找到程序瓶颈

现在我们的整个docker币应用已经有:

  • 10 个 worker
  • 5 个 rng
  • 1 个 hasher
  • 1 个 webui
  • 1 个 redis

为了找到程序瓶颈, 我们可以启动一个临时容器, 对我们的rng和hasher服务做个简单的压力测试.

启动一个临时容器, debug使用alpine镜像, 连接到dockerconins网络中.

# docker service create --network dockercoins --name debug --mode global alpine sleep 1000000000
  • –mode globle 是啥意思呢?global模式的service, 就是在swarm集群的每个节点创建一个容器副本, 所以如果你想让一个service分布在集群的每个节点上,可以使用这个模式.
  • sleep 1000000000是为啥呢?因为懒, 想保持这个容器, 方便我们debug.

下面我们进入debug这个容器, 安装测试软件并对我们的rng和hasher服务进行性能测试.

# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
542eef2e348d alpine:latest "sleep 1000000000" About an hour ago Up About an hour debug.0.4x82pcojee7378nb6z63mlc8l

# docker exec -ti 542eef2e348d sh
/ # hostname
542eef2e348d

安装性能测试工具, curl,ab和drill:

/ # apk add --update curl apache2-utils drill

3.4.1 负载均衡模式

检查rng服务

/ # drill rng
;; ->>HEADER<<- opcode: QUERY, rcode: NOERROR, id: 16923
;; flags: qr rd ra ; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;; rng. IN A
;; ANSWER SECTION:
rng. 600 IN A 10.0.0.6
....

可以看到rng服务的IP地址是10.0.0.6。我们一共有5个rng服务, 为啥只有一个IP地址呢?其实这个IP地址是swarm集群分配给所有rng服务负载均衡的VIP(Virtual IP).

swarm集群负载均衡service有两种方式—VIP和DNSRR:

  • VIP模式每个service会得到一个virtual IP地址作为服务请求的入口。基于virtual IP进行负载均衡.
  • DNSRR模式service利用DNS解析来进行负载均衡, 这种模式在旧的Docker Engine下, 经常行为诡异…所以不推荐.

如何查看service的负载均衡模式呢:

# docker service inspect rng
...
"EndpointSpec": {
"Mode": "vip"
}
},
"Endpoint": {
"Spec": {
"Mode": "vip"
},
"VirtualIPs": [
{
"NetworkID": "396fwpd5ja6azh93dshalmxro",
"Addr": "10.0.0.6/24"
}
]
},
...

指定一个service的模式, 可以在创建service的时候使用如下命令:

docker service create --endpoint-mode [vip|dnssrr] <service name>

修改一个service的模式, 使用如下命令:

docker service update --endpoint-mode [vip|dnssrr] <service name>

3.4.2 rng服务压力测试

介绍完负载均衡模式, 下面使用ab对我们的rng服务进行简单的压力测试.
测试之前, 我们要关掉所有的worker服务, 避免worker服务影响测试结果.

# docker service scale worker=0
worker scaled to 0
# docker service ls
ID NAME REPLICAS IMAGE COMMAND
...
d7g0estex65u worker 0/0 localhost:5000/dockercoins_worker:v0.1

回到我们的debug容器中

a.模拟一个客户端,发送50个请求给rng服务

/ # ab -c 1 -n 50 http://rng/10
This is ApacheBench, Version 2.3 <$Revision: 1748469 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking rng (be patient).....done
Server Software: Werkzeug/0.11.10
Server Hostname: rng
Server Port: 80
Document Path: /10
Document Length: 10 bytes
Concurrency Level: 1
Time taken for tests: 5.386 seconds
Complete requests: 50
Failed requests: 0
Total transferred: 8250 bytes
HTML transferred: 500 bytes
Requests per second: 9.28 [#/sec] (mean)
Time per request: 107.716 [ms] (mean)
Time per request: 107.716 [ms] (mean, across all concurrent requests)
Transfer rate: 1.50 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 1 2 0.6 1 3
Processing: 103 106 1.5 106 110
Waiting: 102 105 1.2 105 109
Total: 104 107 1.7 107 112
WARNING: The median and mean for the initial connection time are not within a normal deviation
These results are probably not that reliable.
Percentage of the requests served within a certain time (ms)
50% 107
66% 108
75% 108
80% 108
90% 110
95% 110
98% 112
99% 112
100% 112 (longest request)

b.模拟50个并发客户端, 发送50个请求

/ # ab -c 50 -n 50 http://rng/10
This is ApacheBench, Version 2.3 <$Revision: 1748469 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking rng (be patient).....done
Server Software: Werkzeug/0.11.10
Server Hostname: rng
Server Port: 80
Document Path: /10
Document Length: 10 bytes
Concurrency Level: 50
Time taken for tests: 1.105 seconds
Complete requests: 50
Failed requests: 0
Total transferred: 8250 bytes
HTML transferred: 500 bytes
Requests per second: 45.23 [#/sec] (mean)
Time per request: 1105.436 [ms] (mean)
Time per request: 22.109 [ms] (mean, across all concurrent requests)
Transfer rate: 7.29 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 7 9 1.3 9 12
Processing: 103 590 313.4 627 1087
Waiting: 103 589 313.3 626 1087
Total: 115 599 312.2 637 1095
Percentage of the requests served within a certain time (ms)
50% 637
66% 764
75% 869
80% 946
90% 1050
95% 1092
98% 1095
99% 1095
100% 1095 (longest request)

可以看出,单个客户端的时候rng的响应时间平均107.716ms, 多并发情况下增加到大约1000ms+.

3.4.3 hasher服务压力测试

hasher的服务测试稍微复杂点, 因为hasher服务需要POST一个随机的bytes数据.
所以我们需要先通过curl制作一个bytes数据文件:
/ # curl http://rng/10 > /tmp/random

a.模拟单客户端,发送50个请求给hasher服务

/ # ab -c 1 -n 50 -T application/octet-stream -p /tmp/random http://hasher/
This is ApacheBench, Version 2.3 <$Revision: 1748469 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking hasher (be patient).....done
Server Software: thin
Server Hostname: hasher
Server Port: 80
Document Path: /
Document Length: 64 bytes
Concurrency Level: 1
Time taken for tests: 5.323 seconds
Complete requests: 50
Failed requests: 0
Total transferred: 10450 bytes
Total body sent: 7250
HTML transferred: 3200 bytes
Requests per second: 9.39 [#/sec] (mean)
Time per request: 106.454 [ms] (mean)
Time per request: 106.454 [ms] (mean, across all concurrent requests)
Transfer rate: 1.92 [Kbytes/sec] received
1.33 kb/s sent
3.25 kb/s total
Connection Times (ms)
min mean[+/-sd] median max
Connect: 1 1 0.4 1 3
Processing: 103 105 0.8 105 107
Waiting: 103 104 0.8 104 107
Total: 104 106 1.0 106 109
Percentage of the requests served within a certain time (ms)
50% 106
66% 106
75% 106
80% 107
90% 108
95% 108
98% 109
99% 109
100% 109 (longest request)

b.模拟50个并发客户端, 发送50个请求

/ # ab -c 50 -n 50 -T application/octet-stream -p /tmp/random http://hasher/
This is ApacheBench, Version 2.3 <$Revision: 1748469 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking hasher (be patient).....done
Server Software: thin
Server Hostname: hasher
Server Port: 80
Document Path: /
Document Length: 64 bytes
Concurrency Level: 50
Time taken for tests: 0.345 seconds
Complete requests: 50
Failed requests: 0
Total transferred: 10450 bytes
Total body sent: 7250
HTML transferred: 3200 bytes
Requests per second: 144.95 [#/sec] (mean)
Time per request: 344.937 [ms] (mean)
Time per request: 6.899 [ms] (mean, across all concurrent requests)
Transfer rate: 29.59 [Kbytes/sec] received
20.53 kb/s sent
50.11 kb/s total
Connection Times (ms)
min mean[+/-sd] median max
Connect: 5 10 4.8 8 17
Processing: 131 214 71.5 238 323
Waiting: 126 207 72.2 231 322
Total: 147 224 67.2 246 328
Percentage of the requests served within a certain time (ms)
50% 246
66% 249
75% 252
80% 314
90% 324
95% 328
98% 328
99% 328
100% 328 (longest request)

从结果可以看出, 单客户端hasher平均响应时间106.454ms, 50并发平均响应时间344.937ms.
hasher服务并发响应时间也慢, 不过比rng的1000+ms却好太多…

3.4.4 程序瓶颈分析

也许你注意到了, 单客户端请求的测试rng平均响应时间约107ms,hasher的响应时间约106ms。这个可能是我们程序的最大瓶颈了。

我们折腾了三章, 搭了swarm集群, Scale了应用。为啥单个请求的时间都在100ms以上呢?!

咳咳, 当你做了很多的优化, 想了很多可能, 应用的性能还是上不去, 这时候一般都是开发挖的坑!!!! 嘿嘿~

下一章, 我们会去看看rng和hasher的代码, 找到单个请求响应时间在100ms左右的原因。通过更新优化代码, 试图缩短应用响应时间。

当然这个系列文章是介绍docker swarm的,所以下一章重点介绍我们的应用程序更新以后如何使用swarm集群roll update容器服务,还会介绍如何搭建一个ELK架构的日志分析平台, 收集分析docker币应用的日志。

K8S中文社区微信公众号
分享到:更多 ()

评论 抢沙发

评论前必须登录!