Redis:發佈訂閱服務使用

應用:

業務解耦:訂單業務後續關聯其餘小組服務,須要同步更新,但不能影響下單主流程,須要經過消息隊列去解耦業務php

涉及到的服務:

  • redis
  • supervisor
  • PHP:Predis/Predis第三方包

使用Docker部署

  • PHP鏡像配置

FROM php:7.3-fpm
MAINTAINER oomcc <baqianxin@163.com>
ARG PHALCON_VERSION=3.4.2
ARG PHALCON_EXT_PATH=php7/64bits

RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \
	&& echo "Asia/Shanghai" > /etc/timezone RUN set -xe && \ # Compile Phalcon curl -LO https://github.com/phalcon/cphalcon/archive/v${PHALCON_VERSION}.tar.gz && \ tar xzf ${PWD}/v${PHALCON_VERSION}.tar.gz && \ docker-php-ext-install -j $(getconf _NPROCESSORS_ONLN) ${PWD}/cphalcon-${PHALCON_VERSION}/build/${PHALCON_EXT_PATH} && \ # Remove all temp files rm -r \ ${PWD}/v${PHALCON_VERSION}.tar.gz \ ${PWD}/cphalcon-${PHALCON_VERSION} ADD sources.list /etc/apt/sources.list RUN apt-get update \ # 相關依賴必須手動安裝 && apt-get install -y \ libfreetype6-dev \ libjpeg62-turbo-dev \ libmcrypt-dev \ libpng-dev \ supervisor \ git \ # 安裝擴展 && docker-php-ext-install -j$(nproc) iconv \ # 若是安裝的擴展須要自定義配置時 && docker-php-ext-configure gd --with-freetype-dir=/usr/include/ --with-jpeg-dir=/usr/include/ \ && docker-php-ext-install -j$(nproc) gd RUN docker-php-ext-install pdo_mysql bcmath \ && docker-php-ext-enable pdo_mysql bcmath RUN pecl install redis \ && docker-php-ext-enable redis COPY extension/docker-php-ext-tideways.ini /usr/local/etc/php/conf.d/docker-php-ext-tideways.ini COPY extension/tideways_xhprof.so /usr/local/lib/php/extensions/no-debug-non-zts-20180731/tideways.so COPY extension/docker-php-ext-mongodb.ini /usr/local/etc/php/conf.d/docker-php-ext-mongodb.ini COPY extension/mongodb.so /usr/local/lib/php/extensions/no-debug-non-zts-20180731/mongodb.so RUN apt-get clean \ && apt-get autoremove WORKDIR /opt # Write Permission RUN usermod -u 1000 www-data EXPOSE 9000 VOLUME [ "/opt" ] 複製代碼
  • supervisor 服務配置

[program:mqworker]
directory = /opt/htdocs/shop.doing ; 程序的啓動目錄
command = php app/console/cli.php redisSub ; 啓動命令,能夠看出與手動在命令行啓動的命令是同樣的
autostart = true     ; 在 supervisord 啓動的時候也自動啓動
startsecs = 5        ; 啓動 5 秒後沒有異常退出,就看成已經正常啓動了
autorestart = true   ; 程序異常退出後自動重啓
startretries = 3     ; 啓動失敗自動重試次數,默認是 3
redirect_stderr = true  ; 把 stderr 重定向到 stdout,默認 false
stdout_logfile_maxbytes = 20MB  ; stdout 日誌文件大小,默認 50MB
stdout_logfile_backups = 20     ; stdout 日誌文件備份數
; stdout 日誌文件,須要注意當指定目錄不存在時沒法正常啓動,因此須要手動建立目錄(supervisord 會自動建立日誌文件)
stdout_logfile = /data/logs/mqworker_stdout.log
; 啓動進程數量
numprocs = 2 ;
process_name = %(process_num)2xxxre

複製代碼
  • Docker-compose服務啓動配置
version: "2"
services:
  nginx:
    build: ./nginx
    ports:
      - "80:80"
    links:
      - "php"
      - "redis"
    volumes:
      - ./www:/opt
      - ./etc/nginx/conf.d:/etc/nginx/conf.d:rw

  php:
    build: ./php
    ports:
      - "9000:9000"
    links:
      - "mysql"
      - "redis"
    volumes:
      - ./www:/opt
      - ./supervisor/conf.d:/etc/supervisor/conf.d

  mysql:
    build: ./mysql
    ports:
      - "3306:3306"
    volumes:
      - ./www/data/mysql:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: 123456

  redis:
    build: ./redis
    ports:
      - "6379:6379"

networks:
  sonarnet:
    driver: bridge
複製代碼

使用Predis

composer install predis/predismysql

發佈:

//命令行發佈
docker exec -it product_redis_1 redis-cli
127.0.0.1:6379> PUBLISH notifications "this is a test"
(integer) 0  //訂閱者數量
127.0.0.1:6379> PUBLISH notifications "this is a test"
(integer) 1 //訂閱者數量
127.0.0.1:6379>
複製代碼
//Predis的發佈
$redisClient = new Predis\Client($single_server + array('read_write_timeout' => 0));
$redisClient->publish('control_channel', '來自XXX的消息');
複製代碼

訂閱:

  • read_write_timeout 設爲0不超時一直等待消息
// Create a client and disable r/w timeout on the socket
$redisClient = new Predis\Client($single_server + array('read_write_timeout' => 0));

// Initialize a new pubsub consumer.
$pubsub = $redisClient->pubSubLoop();

// Subscribe to your channels
$pubsub->subscribe('control_channel', 'notifications');

// Start processing the pubsup messages.
/** @var object $message */
foreach ($pubSub as $message) {
    if ($message->channel == 'control_channel' && $message->payload == 'unsub') {
        print_r('收到取消訂閱的命令:unsub');
        $pubSub->unsubscribe($message->channel);
        print_r('再也不訂閱:' . $message->kind);
    }
    print_r($message);
}
unset($pubSub);
複製代碼

接收示例:

php /opt/htdocs/shop.doing/app/console/cli.php redisSub
stdClass Object
(
    [kind] => subscribe //訂閱成功響應的消息類型
    [channel] => control_channel
    [payload] => 1
)
stdClass Object
(
    [kind] => subscribe
    [channel] => notifications
    [payload] => 2
)
stdClass Object
(
    [kind] => message //發佈的消息類型
    [channel] => notifications
    [payload] => this is a test
)

複製代碼

消息發佈/訂閱成功以後再經過Supervisor服務去啓動守護 nginx

相關文章
相關標籤/搜索