大家好咏闪,年底了款青,年味兒越來(lái)越濃了.2019年的寒冬被定義為未來(lái)10年中最好的一年,對(duì)于這一說(shuō)法悲觀的人和樂(lè)觀的人的理解是不一樣的.但是不管是寒冬還是盛夏誉裆,我們都應(yīng)該堅(jiān)持不斷的積累和主動(dòng)的思考.擁抱變化推正,堅(jiān)定信心.
簡(jiǎn)單描述一下我們的需求恍涂,就是通過(guò)docker 來(lái)搭建一套rabbitmq的集群,用于接受業(yè)務(wù)傳來(lái)的數(shù)據(jù)植榕,然后把數(shù)據(jù)寫(xiě)到消息隊(duì)列中再沧,然后消費(fèi)者消費(fèi)消息,生成日志文件尊残,接著大數(shù)據(jù)采集系統(tǒng)定時(shí)來(lái)采集數(shù)據(jù).這樣做的一個(gè)好處就是炒瘸,我們的服務(wù)可以直接部署到業(yè)務(wù)系統(tǒng)所在的服務(wù)器集群中.
年末的時(shí)候淤堵,在忙完了各種活動(dòng)項(xiàng)目之后,接到了一個(gè)新的項(xiàng)目顷扩,數(shù)據(jù)打點(diǎn)項(xiàng)目.需要在各指定機(jī)房搭建數(shù)據(jù)采集服務(wù)拐邪,然后有數(shù)據(jù)中心定時(shí)去拉取數(shù)據(jù).為此我們采用的解決方案是 基于docker 搭建rabbitmq,利用Openresty 來(lái)進(jìn)行數(shù)據(jù)的生產(chǎn)和nginx代理.來(lái)隘截,讓我們一起了解一些概念.
**以下內(nèi)容是從官網(wǎng)搬來(lái)的:**
OpenResty? 是一個(gè)基于 Nginx 與 Lua 的高性能 Web 平臺(tái)扎阶,其內(nèi)部集成了大量精良的 Lua 庫(kù)、第三方模塊以及大多數(shù)的依賴(lài)項(xiàng)婶芭。用于方便地搭建能夠處理超高并發(fā)东臀、擴(kuò)展性極高的動(dòng)態(tài) Web 應(yīng)用、Web 服務(wù)和動(dòng)態(tài)網(wǎng)關(guān)犀农。
OpenResty? 通過(guò)匯聚各種設(shè)計(jì)精良的 Nginx 模塊(主要由 OpenResty 團(tuán)隊(duì)自主開(kāi)發(fā))啡邑,從而將 Nginx 有效地變成一個(gè)強(qiáng)大的通用 Web 應(yīng)用平臺(tái)。這樣井赌,Web 開(kāi)發(fā)人員和系統(tǒng)工程師可以使用 Lua 腳本語(yǔ)言調(diào)動(dòng) Nginx 支持的各種 C 以及 Lua 模塊谤逼,快速構(gòu)造出足以勝任 10K 乃至 1000K 以上單機(jī)并發(fā)連接的高性能 Web 應(yīng)用系統(tǒng)。
OpenResty? 的目標(biāo)是讓你的Web服務(wù)直接跑在 Nginx 服務(wù)內(nèi)部仇穗,充分利用 Nginx 的非阻塞 I/O 模型流部,不僅僅對(duì) HTTP 客戶(hù)端請(qǐng)求,甚至于對(duì)遠(yuǎn)程后端諸如 MySQL、PostgreSQL纹坐、Memcached 以及 Redis 等都進(jìn)行一致的高性能響應(yīng)枝冀。
之所以選擇OpenResty,是看中了其中nginx服務(wù)和對(duì)lua腳本的支持耘子,nginx可以做服務(wù)代理果漾,lua腳本我們可以用來(lái)編寫(xiě)消息生產(chǎn)者的腳本.好了,開(kāi)始我們的部署之旅吧(再羅嗦一句谷誓,你需要提前了解docker绒障,同時(shí)保證部署環(huán)境已經(jīng)安裝了docker,為了部署成功捍歪,請(qǐng)保證有倆臺(tái)服務(wù)器户辱,或者虛擬機(jī)也行,同時(shí)保持倆臺(tái)服務(wù)器或者虛擬機(jī)的ip在統(tǒng)一網(wǎng)段)糙臼!
一.搭建swarm集群
swarm集群的角色包含有l(wèi)eader庐镐,node 在swarm集群搭建中,重要的是保證 token的一致
1.swarm manager(初始化swarm leader): docker swarm init --advertise-addr 192.168.7.201
提示:這一步會(huì)產(chǎn)生token变逃,token為swarm集群的唯一標(biāo)識(shí)
2.swarm group(成員加入集群)
docker swarm join --token SWMTKN-1-35ucts3e9bg5onl1pyqwh03j1z1micdb88ziq78m4pfr1zulhf-70w2bdzpjyr8xqc1p77mue04r 192.168.7.201:2377
token是在初始化swarm manager時(shí)返回的.
注意:記得為集群成員追加label必逆,便于rabbitmq綁定相應(yīng)的節(jié)點(diǎn),bi-tool-02是節(jié)點(diǎn)名稱(chēng)
docker node update --label-add rabbitmq=master bi-tool-02
docker node update --label-add rabbitmq=slave1 bi-tool-01
這里的label是我們給swarm集群中各節(jié)點(diǎn)起的一個(gè)別名,以 docker node update --label-add rabbitmq=master bi-tool-02 為例名眉,是給節(jié)點(diǎn)bi-tool-02增加標(biāo)簽粟矿,標(biāo)簽為: rabbitmq=master ,我們可以通過(guò) docker node inspect bi-tool-02 來(lái)查看節(jié)點(diǎn)配置內(nèi)容.可以看到的內(nèi)容如下:
"Labels": {
"rabbitmq": "master"
},
追加標(biāo)簽的目的是為了我們?cè)诖罱╮abbitmq集群的時(shí)候璧针,方便rabbitmq節(jié)點(diǎn)的綁定.
二.啟動(dòng)network服務(wù)
network 用于提供容器間通許
**命令:**docker network create --driver overlay rabbitmq-network
三.搭建rabbitmq集群
1.創(chuàng)建鏡像
docker build -t stomp-rabbitmq:latest .
創(chuàng)建鏡像所需要的dockerfile文件見(jiàn)附件 (博客園不能上傳附件嗎?渊啰?探橱??等我咨詢(xún)完了绘证,我再補(bǔ)充這個(gè)附件)
放在了百度網(wǎng)盤(pán)上:
https://pan.baidu.com/s/1PI1nL6TL9pJxsWUaTBleig
提取碼:sg9p
**2.創(chuàng)建rabbitmq master隊(duì)列**
命令(master):sudo docker service create --name stomp-rabbitmq-master --hostname="stomp-rabbitmq-master" --network rabbitmq-network -p 5772:5672 -p 15772:15672 -p 12345:12345 --mount type=bind,target=/var/lib/rabbitmq/,source=/home/agent/rabmq/ --constraint node.labels.rabbitmq==master -e RABBITMQ_CLUSTER_NODES='rabbit@stomp-rabbitmq-slave1' -e "AUTOCLUSTER_CLEANUP=true" -e "CLEANUP_WARN_ONLY=false" -e "RABBITMQ_ERLANG_COOKIE=thisissecretkey" stomp-rabbitmq:latest
注意:要確保/home/agent/rabmq/ 路徑的存在
備注:
--network 為設(shè)置網(wǎng)絡(luò)環(huán)境隧膏,rabbitmq-network是創(chuàng)建好的docker network,類(lèi)型為overlay嚷那。
-p 為將容器的端口暴露到宿主機(jī)的端口上胞枕,這樣可以通過(guò)宿主機(jī)也就是服務(wù)器的端口訪問(wèn)到容器對(duì)應(yīng)的端口,前方前為宿主機(jī)端口魏宽,后方為容器端口腐泻。其中5672為amqp通信端口,15672為管理界面端口队询,12345為stomp通信端口派桩。
--mount 為將容器內(nèi)的目錄映射到宿主機(jī)上(/var/lib/rabbitmq/ 保存了隊(duì)列與交換機(jī)等的信息,而且保存了持久化的隊(duì)列里的消息)蚌斩,這樣當(dāng)容器出現(xiàn)問(wèn)題時(shí)铆惑,啟動(dòng)新容器時(shí)由于已經(jīng)掛載到了宿主機(jī)上持久化,關(guān)鍵信息可以不丟失送膳,新容器相當(dāng)于和舊容器一樣员魏。前方為容器,后方為宿主機(jī)目錄叠聋。
--constraint 為創(chuàng)建service時(shí)將service指定在某臺(tái)機(jī)器上創(chuàng)建撕阎,本次使用的是通過(guò)lable指定,在之前我已經(jīng)對(duì)這三臺(tái)服務(wù)器進(jìn)行了label指定碌补。
-e 為指定容器內(nèi)的環(huán)境變量闻书,比如其中的 "RABBITMQ_ERLANG_COOKIE=thisissecretkey"
**3.創(chuàng)建rabbitmq slave 隊(duì)列**
命令(slave):sudo docker service create --name stomp-rabbitmq-slave1 --hostname="stomp-rabbitmq-slave1" --network rabbitmq-network -p 5773:5672 -p 15773:15672 -p 23456:12345 --mount type=bind,target=/var/lib/rabbitmq/,source=/home/agent/rabmq/ --constraint node.labels.rabbitmq==slave1 -e RABBITMQ_CLUSTER_NODES='rabbit@rabbitmq-master' -e "AUTOCLUSTER_CLEANUP=true" -e "CLEANUP_WARN_ONLY=false" -e "RABBITMQ_ERLANG_COOKIE=thisissecretkey" stomp-rabbitmq:latest
在執(zhí)行完 sudo docker service create --name stomp-rabbitmq-slave1 后,其實(shí)就相當(dāng)于啟動(dòng)了一個(gè)容器脑慧,可以通過(guò) docker ps 看到魄眉,如果看不到,那說(shuō)明服務(wù)啟動(dòng)失敗闷袒,通過(guò)進(jìn)程守護(hù)進(jìn)入容器用到的 id 就是 此處看到的id
(將分支1加入到集群)坑律,通過(guò)守護(hù)進(jìn)程進(jìn)入到容器內(nèi)部執(zhí)行
(進(jìn)入容器)命令:docker exec -it **36383eefcf87** /bin/sh
docker exec -it /bin/sh
rabbitmqctl stop_app
rabbitmqctl join_cluster rabbit@stomp-rabbitmq-master
rabbitmqctl start_app
4.創(chuàng)建Openresty(nginx+lua)
docker build -t openresty-product:0.0.1 .
命令:docker service create --name openresty-product-service --mode global -p 8080:80 --mount type=bind,target=/var/log/nginx/,source=/home/agent/openresty-file/var/log/nginx --mount type=bind,target=/opt/,source=/home/agent/openresty-file/openrestyFile --mount type=bind,target=/etc/nginx/conf.d,source=/home/agent/openresty-file/etc/nginx/conf.d --mount type=bind,target=/usr/local/openresty/nginx/conf,source=/home/agent/openresty-file/usr/local/openresty/nginx/conf openresty-product:0.0.1
用于外網(wǎng)訪問(wèn)下載數(shù)據(jù)文件
命令:dockerservice create --name openresty-file-server --constraint node.labels.rabbitmq==master -p 80:80 --mount type=bind,target=/var/log/nginx/,source=/home/agent/finalDataFile/var/log/nginx --mount type=bind,target=/opt/,source=/home/agent/finalDataFile --mount type=bind,target=/etc/nginx/conf.d,source=/home/agent/finalDataFile/etc/nginx/conf.d openresty/openresty:xenial
nginx 的相關(guān)配置,我們就不在此細(xì)說(shuō)了,我可以給大家看個(gè)例子
server {
listen 80;
server_name localhost;
#charset koi8-r;
access_log /var/log/nginx/host.access.log main;
location / {
root /usr/local/openresty/nginx/html;
index index.html index.htm;
}
location /hello {
# root /usr/local/openresty/nginx/html;
# index index.html index.htm;
default_type 'text/html';
content_by_lua 'ngx.say("hello world")';
}
location /file {
proxy_pass http://192.168.7.201:8090/;
access_log /var/log/nginx/file.access.log main;
error_log /var/log/nginx/file.error.log;
}
location /dataagent/v1/test {
# deny all;
default_type 'text/html';
# lua_code_cache off;
# content_by_lua 'ngx.say("test.test.com access")';
access_log /var/log/nginx/chaoshen.access.log main;
error_log /var/log/nginx/chaoshen.error.log;
content_by_lua_file /opt/openresty-docker/openresty/lua-dataagent/chaoshen_yuenan.lua;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/local/openresty/nginx/html;
}
}
配置中 /dataagent/v1/test content_by_lua_file 對(duì)應(yīng)的腳本文件就是用來(lái)生產(chǎn)消息的晃择,我們也直接來(lái)看代碼
package.path = '/opt/openresty-docker/openresty/lua-dataagent/lib/resty/?.lua;'
local rabbitmq = require "rabbitmqstomp"
local opts = {
username = 'guest',
password = 'guest',
vhost = '/'
}
local mq, err = rabbitmq:new(opts)
if not mq then
ngx.log(4,'cannot new mq')
ngx.log(4,err)
return
end
mq:set_timeout(60000)
-- connect to the rabbitmq on local machine
local ok, err = mq:connect('192.168.7.201', 12345)
if not ok then
-- connect to other rabbitmq in cluster
ok, err = mq:connect('192.168.7.200', 23456)
if not ok then
-- connect to last rabbitmq in cluster
-- put messages into errorLog
ngx.log(4,'cannot connect mq')
ngx.log(4,err)
return
end
end
-- local msg = "d.g.test.com/gp.do?ac=s_publishgame&action=login&appId=133214321432&serverId=bj_server1&channel=test_gamecenter&accountId=q1132143214&playerId=q1132143214&tm=1458874365&first=1"
local msg = string.sub(ngx.var.request_uri,22,-1)
local result = string.gsub(msg,".*/","d.g.test.com/",1)
local send_receipt_id = ngx.now()*1000
local headers = {}
headers["destination"] = "/exchange/statistical/statistical.test"
headers["receipt"] = send_receipt_id
headers["app-id"] = "luaresty"
headers["persistent"] = "true"
headers["content-type"] = "application/plian"
local ok, err = mq:send(result, headers)
if not ok then
ngx.log(4,'cannot send mq')
ngx.log(4,err)
return
end
local ok, err = mq:set_keepalive(10000, 100)
if not ok then
ngx.log(4,'cannot set_keepalive mq')
ngx.log(4,err)
return
end
-- ngx.say('success: ',msg)
5.配置RabbitMq
RabbitMq比較好的一個(gè)資料站點(diǎn):http://www.reibang.com/p/124cda48e4ea
http://www.reibang.com/p/61a90fba1d2a
交換機(jī)冀值,statistical
路由規(guī)則,[ statistical.t](https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxcheckurl?requrl=http%3A%2F%2Fstatistical.saiche&skey=%40crypt_5c9ecbfe_ff781212a41fc3abe64a1ae9820cad9a&deviceid=e270398035265328&pass_ticket=PHgh7%252BM86RzGhmsfz1Xwdg81jTbPVAYPpyAn3gn%252Fiog%253D&opcode=2&scene=1&username=@1cda7a7a127faf122dea2ec2e5b3caa5)est
隊(duì)列宫屠,test
在rabbitmq中建好列疗,就能往里發(fā)消息了
添加 "交換機(jī)"浪蹂,"路由規(guī)則"抵栈,"消息隊(duì)列"
//聲明交換機(jī)
rabbitmqctl eval 'rabbit_exchange:declare({resource, <<"/">>, exchange, <<"statistical">>}, topic, true, false, false, []).'
//聲明消息隊(duì)列
rabbitmqctl eval 'rabbit_amqqueue:declare({resource, <<"/">>, queue, <<"test">>}, true, false, [], none).'
//綁定交換機(jī),路由規(guī)則坤次,消息隊(duì)列
rabbitmqctl eval 'rabbit_binding:add({binding, {resource, <<"/">>, exchange, <<"statistical">>}, <<"statistical.test">>, {resource, <<"/">>, queue, <<"test">>}, []}).'
6.測(cè)試消息生產(chǎn)
curl -i "http://192.168.7.200:8080/dataagent/v1/test/topic-sendtime-id/d.g.test.com/gp.do"
重點(diǎn)提示:
1.首先要理解集群的架構(gòu)
2.保證打點(diǎn)日志文件的存儲(chǔ)空間足夠大
3.了解openresty
openresty:是一個(gè)基于 Nginx 與 Lua 的高性能 Web 平臺(tái)古劲,其內(nèi)部集成了大量精良的 Lua 庫(kù)、第三方模塊以及大多數(shù)的依賴(lài)項(xiàng)缰猴。用于方便地搭建能夠處理超高并發(fā)产艾、擴(kuò)展性極高的動(dòng)態(tài) Web 應(yīng)用、Web 服務(wù)和動(dòng)態(tài)網(wǎng)關(guān)滑绒。
4.要了解rabbitmq的相關(guān)知識(shí)闷堡,保證交換機(jī),路由疑故,消息隊(duì)列的正常創(chuàng)建
5.注意容器中配置文件和物理路徑的映射關(guān)系
6.lua腳本中缚窿,rabbitMq的地址一版是內(nèi)網(wǎng)(局域網(wǎng))地址
7.swarm集群中,注意個(gè)集群節(jié)點(diǎn) label 的自定義
上面都有關(guān)于此問(wèn)題的描述
問(wèn)題排查思路:
1.查看nginx 日志來(lái)排查nginx異常日志
2.理解架構(gòu)途中消息的傳遞路徑焰扳,順著路近一步步追查
好了倦零,就寫(xiě)道這里,我是jerry百