date: 2018-09-03 21:30:23
title: php| 初探 rabbitmq
description: 零零散散折騰了 rabbitmq 幾次, 歸納總結(jié)一下先
經(jīng)常看到消息隊(duì)列( MQ ), 實(shí)戰(zhàn)中比較少, 說說我的一些粗線的理解:
- 引入消息隊(duì)列, 使系統(tǒng)之間解耦 -> 當(dāng)然還有很多 小型項(xiàng)目 使用 重項(xiàng)目 的方式(系統(tǒng)拆分, 不存在的!); 解耦這部分的內(nèi)容, 后來還會講到
- 通過將流程 異步化, 增加每部分的吞吐能力, 從而實(shí)現(xiàn)最終增加系統(tǒng)性能, 這一點(diǎn)有點(diǎn)類似服務(wù)器領(lǐng)域的 同步 -> 異步/協(xié)程, 可以參考 swoole| swoole 協(xié)程初體驗(yàn)
當(dāng)然, 實(shí)踐出真知, 還是希望能在業(yè)務(wù)中多實(shí)戰(zhàn), 或者參與相關(guān)的開源項(xiàng)目~
相關(guān)教程
老生常談, 生命周期思維方式, 想一想消息是怎么在整個(gè)消息隊(duì)列系統(tǒng)中流動的.
RabbitMQ與AMQP協(xié)議詳解: 強(qiáng)烈推薦, 理解基礎(chǔ)概念非常好的一篇文章
PHP消息隊(duì)列實(shí)現(xiàn)及應(yīng)用: 簡單入門級, 不用糾結(jié)代碼, 關(guān)注應(yīng)用場景和解決方式
應(yīng)用場景: 冗余 解耦 流量削峰 異步通信 擴(kuò)展新 排序保證 -> 隊(duì)列結(jié)構(gòu)的中間件
隊(duì)列介質(zhì): mysql redis 消息隊(duì)列服務(wù)(rabbitmq kafka)
觸發(fā)機(jī)制: 死循環(huán)while 定時(shí)腳本cron 守護(hù)進(jìn)程daemon(fpm)
場景一 訂單系統(tǒng)/配送系統(tǒng)解耦: 訂單系統(tǒng) -> 隊(duì)列表 -> 配送系統(tǒng)
場景二 流量削峰: redis list類型實(shí)現(xiàn)定長隊(duì)列, 請求先入隊(duì)列, 超出隊(duì)列長度后的請求丟棄
rabbitmq架構(gòu)和原理: 完整實(shí)現(xiàn)AMQP 集群簡化 持久化 跨平臺
基于 AMQP(advanced message queue protocol, 高級消息隊(duì)列協(xié)議)
集群模式: 表達(dá)式配置 HA模式 鏡像隊(duì)列模式
保證數(shù)據(jù)不丟失/高可靠/高可用
安裝 rabbitmq
老生常談, 直接上 docker:
- docker環(huán)境快速安裝: 阿里云提供, 安裝/加速 全搞定
docker-compose, 使用 rabbitmq 官方鏡像:
version: '3'
services:
rabbitmq: # https://hub.docker.com/_/rabbitmq/
image: rabbitmq:3.7.7-management-alpine
hostname: myrabbitmq
ports:
- "5672:5672" # mq
- "15672:15672" # admin
就這么幾行, rabbitmq 就配置好了, 使用 docker-compose up -d rabbit 啟動, 大功告成
這里使用的 management 版本的 rabbitmq, 管理控制臺地址 http://localhost:15672, 初始密碼 guest/guest
進(jìn)入容器內(nèi)部看看:
# 進(jìn)入容器
docker-compose exec rabbitmq bash
# 查看啟動的服務(wù)
bash-4.4# ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
rabbitmq 1 0.0 0.0 1612 1012 ? Ss 06:25 0:00 /bin/sh /opt/rabbitmq/sbin/rabbitmq-server
rabbitmq 90 0.0 0.0 1068 660 ? S 06:25 0:00 /usr/lib/erlang/erts-9.3/bin/epmd -daemon
rabbitmq 158 0.5 3.9 1707624 81152 ? Sl 06:25 0:37 /usr/lib/erlang/erts-9.3/bin/beam.smp -W w -A 64 -MBas ageffcbf -MHas ageffcbf -MBlmbcs 512 -MHlmbcs 512 -MMmcs 30 -P 1048576 -t 5000000 -s
rabbitmq 265 0.0 0.0 752 536 ? Ss 06:25 0:00 erl_child_setup 1048576
rabbitmq 306 0.0 0.0 772 4 ? Ss 06:25 0:00 inet_gethost 4
rabbitmq 307 0.0 0.0 772 32 ? S 06:25 0:00 inet_gethost 4
root 3258 0.0 0.0 6364 2004 pts/0 Ss 07:25 0:00 bash
root 6813 0.0 0.0 5696 628 pts/0 R+ 08:23 0:00 ps aux
# rabbitmq 相關(guān)命令行命令
bash-4.4# rabbitmq
rabbitmq-defaults rabbitmq-diagnostics rabbitmq-env rabbitmq-plugins rabbitmq-server rabbitmqadmin rabbitmqctl
- rabbitmqctl: rabbitmq control
- rabbitmq-plugins: 也可以通過 rabbitmq-plugins 來開啟管理控制臺
更多配置, 可以訪問 rabbitmq鏡像官網(wǎng) 進(jìn)行查看
快速開始
rabbitmq 官方文檔 非常完善與清晰, 值得花時(shí)間看看
新手快速入門文檔, 代碼 - rabbitmq/rabbitmq-tutorials
rabbitmq 支持多種語言的 client, 這里說明支持的 php client:
- php-amqplib: compoer package, 入門 rabbitmq 最簡單的方式,
composer require即可完成安裝 - ext-amqp: PHP擴(kuò)展, 需要安裝
ext-amqp擴(kuò)展, 性能更優(yōu)
queue-interop 按下不表, 還沒進(jìn)入 PSR.
官方的快速入門手冊:
- hello world
消息隊(duì)列最基礎(chǔ)的三個(gè)概念, 生產(chǎn)者producer + 消息隊(duì)列MQ + 消費(fèi)者consumer

- work queues
如果 消費(fèi)者的消費(fèi)能力不足 怎么辦? 多開幾個(gè) consumer 唄. 多個(gè) consumer 怎么分擔(dān) MQ 中的消息呢? 所以在 消息隊(duì)列MQ 和 消費(fèi)者consumer 之間進(jìn)行 負(fù)載均衡LB. LB并不是準(zhǔn)去的說法, 通常的說法是消費(fèi)者 訂閱 消息隊(duì)列的內(nèi)容. 在我看來, LB 更有表現(xiàn)力 -- 消費(fèi)能力不足導(dǎo)致需要多個(gè)消費(fèi)者, 怎么和 web server 并發(fā)不夠, 加機(jī)器加 LB 有些像呢?
這里我使用的 LB 這樣的概念, 目的在于 LB 在服務(wù)器領(lǐng)域太常見了, 包含很多內(nèi)容, 需要細(xì)細(xì)體會

- pub/sub
發(fā)布訂閱, 看起來像多個(gè) hello world, 注意圖里多了一個(gè) rabbitmq 中的新概念 交換器exchange(圖中簡寫為 X), 在 生產(chǎn)者producer 和 消息隊(duì)列MQ 之間, 由 exchange 來決定消息 分發(fā) 到哪個(gè) MQ 中

- routing/topic
兩個(gè)新的概念, 路由功能 和 主體訂閱 功能, 而這些都和 交換器exchange 有關(guān), 涉及到的配置: 交換器類型(exchange type) + 路由key(routing key) + 綁定key(binding key). 為啥會這么復(fù)雜呢? 干嘛要這么多配置?
一言以蔽之, 決定 生產(chǎn)者producer 產(chǎn)生的消息, 投遞到哪個(gè) 消息隊(duì)列MQ 中, 最終又由哪個(gè) consumer 消費(fèi)


- RPC
新玩法, 通過消息隊(duì)列實(shí)現(xiàn) 遠(yuǎn)程過程調(diào)用RPC 的效果

我在這里并沒有貼具體代碼, 一則因?yàn)楣俜浇o的代碼確實(shí)適合上手, 更重要是因?yàn)? 理解 rabbitmq 究竟是個(gè)什么玩意 更重要
rabbitmq 究竟是啥
- 首先是 MQ 最基礎(chǔ)的概念: 生產(chǎn)者producer + 消息隊(duì)列MQ(狹義指存儲消息的隊(duì)列類型的數(shù)據(jù)結(jié)構(gòu)) + 消費(fèi)者consumer
- consumer 怎么從 MQ 中獲取消息 + consumer獲取消息后確認(rèn)(ack): 可以近似理解 MQ 和 consumer 之間需要一層 LB
- producer 怎么投遞消息到 MQ 中: exchange + exchange type + routing key + binding key -> 消息路由/主題訂閱
- 怎么擴(kuò)展 MQ 的性能呢: 集群, 涉及到集群, 又會新增很多概念了
放幾張圖輔助理解:

- 實(shí)際使用過程中, 還需要 tcp 連接相關(guān)的概念: connection + channel

- 這張圖可以看到消息msg 的 生命周期

寫在最后
正兒八經(jīng)(準(zhǔn)確說, 這叫 專業(yè)) 的消息隊(duì)列, 架構(gòu)設(shè)計(jì)上確實(shí)有一定的復(fù)雜性, 而且為了滿足高性能, 還會有很多性能優(yōu)化的點(diǎn) -- 學(xué)習(xí)消息隊(duì)列, 長路漫漫, 可以好好折騰一番了~