Docker swarm结合Openresty部署rabbitmq集群

大家好,年底了,年味儿越来越浓了.2019年的寒冬被定义为未来10年中最好的一年,对于这一说法悲观的人和乐观的人的理解是不一样的.但是不管是寒冬还是盛夏,我们都应该坚持不断的积累和主动的思考.拥抱变化,坚定信心.

    简单描述一下我们的需求,就是通过docker 来搭建一套rabbitmq的集群,用于接受业务传来的数据,然后把数据写到消息队列中,然后消费者消费消息,生成日志文件,接着大数据采集系统定时来采集数据.这样做的一个好处就是,我们的服务可以直接部署到业务系统所在的服务器集群中.     

年末的时候,在忙完了各种活动项目之后,接到了一个新的项目,数据打点项目.需要在各指定机房搭建数据采集服务,然后有数据中心定时去拉取数据.为此我们采用的解决方案是 基于docker 搭建rabbitmq,利用Openresty 来进行数据的生产和nginx代理.来,让我们一起了解一些概念.

   **以下内容是从官网搬来的:**

OpenResty® 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。

OpenResty® 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地变成一个强大的通用 Web 应用平台。这样,Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。

OpenResty® 的目标是让你的Web服务直接跑在 Nginx 服务内部,充分利用 Nginx 的非阻塞 I/O 模型,不仅仅对 HTTP 客户端请求,甚至于对远程后端诸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都进行一致的高性能响应。

之所以选择OpenResty,是看中了其中nginx服务和对lua脚本的支持,nginx可以做服务代理,lua脚本我们可以用来编写消息生产者的脚本.好了,开始我们的部署之旅吧(再罗嗦一句,你需要提前了解docker,同时保证部署环境已经安装了docker,为了部署成功,请保证有俩台服务器,或者虚拟机也行,同时保持俩台服务器或者虚拟机的ip在统一网段)!

一.搭建swarm集群

swarm集群的角色包含有leader,node 在swarm集群搭建中,重要的是保证 token的一致

   1.swarm manager(初始化swarm leader): docker swarm init --advertise-addr 192.168.7.201             

     提示:这一步会产生token,token为swarm集群的唯一标识

2.swarm group(成员加入集群)

docker swarm join --token SWMTKN-1-35ucts3e9bg5onl1pyqwh03j1z1micdb88ziq78m4pfr1zulhf-70w2bdzpjyr8xqc1p77mue04r 192.168.7.201:2377

     token是在初始化swarm manager时返回的.

注意:记得为集群成员追加label,便于rabbitmq绑定相应的节点,bi-tool-02是节点名称

docker node update --label-add rabbitmq=master bi-tool-02

docker node update --label-add rabbitmq=slave1 bi-tool-01

    这里的label是我们给swarm集群中各节点起的一个别名,以 docker node update --label-add rabbitmq=master bi-tool-02 为例,是给节点bi-tool-02增加标签,标签为: rabbitmq=master  ,我们可以通过 docker node inspect bi-tool-02 来查看节点配置内容.可以看到的内容如下:

"Labels": {

"rabbitmq": "master"

},

追加标签的目的是为了我们在搭建rabbitmq集群的时候,方便rabbitmq节点的绑定.

二.启动network服务

network 用于提供容器间通许

   **命令:**docker network create --driver overlay rabbitmq-network

三.搭建rabbitmq集群

1.创建镜像

docker build -t stomp-rabbitmq:latest .

    创建镜像所需要的dockerfile文件见附件 (博客园不能上传附件吗????等我咨询完了,我再补充这个附件)

    放在了百度网盘上:

https://pan.baidu.com/s/1PI1nL6TL9pJxsWUaTBleig

    提取码:sg9p            

    **2.创建rabbitmq master队列**

命令(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 为设置网络环境,rabbitmq-network是创建好的docker network,类型为overlay。

-p 为将容器的端口暴露到宿主机的端口上,这样可以通过宿主机也就是服务器的端口访问到容器对应的端口,前方前为宿主机端口,后方为容器端口。其中5672为amqp通信端口,15672为管理界面端口,12345为stomp通信端口。

--mount 为将容器内的目录映射到宿主机上(/var/lib/rabbitmq/ 保存了队列与交换机等的信息,而且保存了持久化的队列里的消息),这样当容器出现问题时,启动新容器时由于已经挂载到了宿主机上持久化,关键信息可以不丢失,新容器相当于和旧容器一样。前方为容器,后方为宿主机目录。

--constraint 为创建service时将service指定在某台机器上创建,本次使用的是通过lable指定,在之前我已经对这三台服务器进行了label指定。

-e 为指定容器内的环境变量,比如其中的 "RABBITMQ_ERLANG_COOKIE=thisissecretkey"

   **3.创建rabbitmq slave 队列**

  命令(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

    在执行完 sudo docker service create --name stomp-rabbitmq-slave1 后,其实就相当于启动了一个容器,可以通过 docker ps 看到,如果看不到,那说明服务启动失败,通过进程守护进入容器用到的 id 就是 此处看到的id

(将分支1加入到集群),通过守护进程进入到容器内部执行

    (进入容器)命令: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.创建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

用于外网访问下载数据文件
命令: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 的相关配置,我们就不在此细说了,我可以给大家看个例子
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 对应的脚本文件就是用来生产消息的,我们也直接来看代码

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比较好的一个资料站点:https://www.jianshu.com/p/124cda48e4ea

                    https://www.jianshu.com/p/61a90fba1d2a

           交换机,statistical
           路由规则,[ 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
           队列,test
           在rabbitmq中建好,就能往里发消息了

添加 "交换机","路由规则","消息队列"

    //声明交换机

rabbitmqctl eval 'rabbit_exchange:declare({resource, <<"/">>, exchange, <<"statistical">>}, topic, true, false, false, []).'

    //声明消息队列
    rabbitmqctl eval 'rabbit_amqqueue:declare({resource, <<"/">>, queue, <<"test">>}, true, false, [], none).'

    //绑定交换机,路由规则,消息队列
    rabbitmqctl eval 'rabbit_binding:add({binding, {resource, <<"/">>, exchange, <<"statistical">>}, <<"statistical.test">>, {resource, <<"/">>, queue, <<"test">>}, []}).'

6.测试消息生产

curl -i "http://192.168.7.200:8080/dataagent/v1/test/topic-sendtime-id/d.g.test.com/gp.do"

  重点提示:

1.首先要理解集群的架构

2.保证打点日志文件的存储空间足够大

3.了解openresty

openresty:是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。

4.要了解rabbitmq的相关知识,保证交换机,路由,消息队列的正常创建

5.注意容器中配置文件和物理路径的映射关系

6.lua脚本中,rabbitMq的地址一版是内网(局域网)地址

7.swarm集群中,注意个集群节点 label 的自定义

上面都有关于此问题的描述

  问题排查思路:

1.查看nginx 日志来排查nginx异常日志

2.理解架构途中消息的传递路径,顺着路近一步步追查

好了,就写道这里,我是jerry百

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容