• laravel使用redis监听在内部再次使用redis遇到的问题


    问题一:启用监听收不到过期时间消息,原因是未开启配置
    解决办法是 在redis配置文件内开启 notify-keyspace-events Ex或者在redis命令行 redis-cli 使用命令:

    config set notify-keyspace-events Ex

    问题二:PredisConnectionConnectionException : Error while reading line from the server

    原因是Redis默认链接时间未60秒,在database.php设置read_write_timeout为0即可。

    "read_write_timeout"=>0

    问题三:ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in this context
    这个是因为一个Redis链接使用监听时,无法使用其他命令。需要重新建立一个链接。期初我使用 new PredisClient(),一直报错,我也不知道为啥。然后我想到了使用集群,使用相同配置。将监听事件设置为单独实例。具体操作如下:

    //datebase.php配置页面
    'redis' => [
            'client' => 'predis',
            'default' => [
                'host' => env('REDIS_HOST', '127.0.0.1'),
                'password' => env('REDIS_PASSWORD', null),
                'port' => env('REDIS_PORT', 6379),
                'database' => 0,
                "queue" => '{default}',//queue站点默认走的redis
            ],
            'publisher' => [ //redis 订阅监听
                        'host' => env('REDIS_HOST', '127.0.0.1'),
                        'password' => env('REDIS_PASSWORD', null),
                        'port' => env('REDIS_PORT', 6379),
                        'database' => 0,
                        "read_write_timeout"=>0,//长连接不要断
                    ],
               ]
    //监听页面
    //__keyevent@*__:expired监听过期消息
    $redis=Redis::connection('publisher');//创建新的实例
    $redis->psubscribe(['__keyevent@*__:expired'], function ($message, $channel) {
       echo $message;
       Redis::set('aa','123');//这样就不会报错了。这里使用的是default的,是两个redis链接。
    });

    Pub/Sub:
    "发布/订阅"在redis中,被设计的非常轻量级和简洁,它做到了消息的“发布”和“订阅”的
    基本能力;但是尚未提供关于消息的持久化等各种企业级的特性。

    一个Redis client发布消息,其他多个redis client订阅消息,发布的消息“即发即失”,redis
    不会持久保存发布的消息;消息订阅者也将只能得到订阅之后的消息,通道中此前的消息将无
    从获得。

    消息发布者,即publish客户端,无需独占链接,你可以在publish消息的同时,使用同一个redis-client链接进行其他操作(例如:INCR等)
    消息订阅者,即subscribe客户端,需要独占链接,即进行subscribe期间,redis-client无法穿插其他操作,
    此时client以阻塞的方式等待“publish端”的消息;因此这里subscribe端需要使用单独的链接,甚至需要在额外的线程中使用。
    Tcp默认连接时间固定,如果在这时间内sub端没有接收到pub端消息,或pub端没有消息产生,sub端的连接都会被强制回收,
    这里就需要使用特殊手段解决,用定时器来模拟pub和sub之间的保活机制,定时器时间不能超过TCP最大连接时间,具体根据机器环境来定;

    一旦subscribe端断开链接,将会失去部分消息,即链接失效期间的消息将会丢失,所以这里就需要考虑到借助redis的list来持久化;

    如果你非常关注每个消息,那么你应该基于Redis做一些额外的补充工作,如果你期望订阅是持久的,那么如下的设计思路可以借鉴:

    1) subscribe端:
    首先向一个Set集合中增加“订阅者ID”, 此Set集合保存了“活跃订阅”者,
    订阅者ID标记每个唯一的订阅者,此Set为 "活跃订阅者集合"

    2) subcribe端开启订阅操作,并基于Redis创建一个以 "订阅者ID" 为KEY的LIST数据结构,
    此LIST中存储了所有的尚未消费的消息,此List称为 "订阅者消息队列"

    3) publish端:
    每发布一条消息之后,publish端都需要遍历 "活跃订阅者集合",并依次
    向每个 "订阅者消息队列" 尾部追加此次发布的消息.

    4) 到此为止,我们可以基本保证,发布的每一条消息,都会持久保存在每个 "订阅者消息队列" 中.

    5) subscribe端,每收到一个订阅消息,在消费之后,必须删除自己的 "订阅者消息队列" 头部的一条记录.

    6) subscribe端启动时,如果发现自己的 "订阅者消息队列" 有残存记录, 那么将会首先消费这些记录,然后再去订阅.

    以上方法可以保证成功到达的消息必消费不丢失;
    但还是会存在ngx业务机方自丢失数据问题,也就是ngx业务机自身问题或网络问题导致ngx业务机发布的消息没有送达redis机器;
    更完善的确认机制才能彻底解决上述存在问题;

    注意,在实际ngx_lua_redis应用中,redis单个客户端订阅模式下仅能使用有限的几个命令,不能使用其它结构命令,如lpop,rpush等;
    因为 publish是普通的request/response模式, 但subscribe不是,否则会报错:
          ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / PING / QUIT allowed in this cont
    关于这点以下是官网一般解释:
    You are required to use two connections for pub and sub. A subscriber connection cannot issue any commands
    other than subscribe, psubscribe, unsubscribe, punsubscribe (although @Antirez has hinted of a subscriber-safe
    ping in the future). If you try to do anything else, redis tells you:
    -ERR only (P)SUBSCRIBE / (P)UNSUBSCRIBE / QUIT allowed in this context
    (note that you can't test this with redis-cli, since that understands the protocol well enough to prevent you
    from issuing commands once you have subscribed - but any other basic socket tool should work fine)
    This is because subscriber connections work very differently - rather than working on a request/response basis,
    incoming messages can now come in at any time, unsolicited.
    publish is a regular request/response command, so must be sent on a regular connection, not a subscriber connection.

  • 相关阅读:
    Activiti:入门
    Activiti:整合WEB版流程模型设计器Modeler
    Activiti:流程定义部署管理
    Activiti:流程实例管理
    Activiti:基本实操
    Activiti:流程任务管理
    IDEA全局搜索,File Mask筛选列表为空问题解决
    【Electron】使用 buildtools 在 Windows 中编译 electron
    【Electron】在 WSL2 中 打包 electron Linux 版本应用及运行
    对既有磁盘挂载进行扩容,对既有逻辑卷进行扩容 resize2fs
  • 原文地址:https://www.cnblogs.com/matengfei123/p/12293124.html
Copyright © 2020-2023  润新知