在第一章 (Docker 1.12 Swarm Mode集群实战(第一章))和过渡篇中 (Docker 1.12 Swarm Mode集群实战(过渡篇)之Registry和Image) 我们理解了在Swarm上运行Docker币应用的背景和瓶颈,并且将集群环境中私有Registry和Image准备完毕。本章内容将正式部署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币应用的日志。
评论前必须登录!
注册