redis-haproxy-从服务器读取线路时出错

a11xaf1n  于 2021-06-10  发布在  Redis
关注(0)|答案(1)|浏览(366)

抱歉的标题,这可能听起来像一个“准备好回答”的主题,但我相信我的情况是独一无二的。
另外,这是我的第一篇文章,所以我很抱歉,如果我没有在正确的渠道,因为我不确定我的问题是在服务器管理方面还是laravel的配置方面。
我正在尝试获得一些新的想法,如何解决horizon/predis/haproxy的问题,我认为这个问题已经解决了,但现在又出现了。

关于环境的一些细节

2台apache服务器:php版本7.2.29-1+ubuntu18.04.1+deb.sury.org+1
线程安全被禁用,我们使用fpm
使用简单的主从设置(无高可用性,无sentinel)的2x redis服务器:redis版本4.0.9
haproxy 1.9版的负载平衡

图书馆

laravel/框架:6.14.0
拉威尔/地平线“:3.7.2
redis/predis:1.1.1

地平线配置

horizon守护进程通过supervisor进行管理。
这是中的redis客户端配置 config/database.php :

'redis' => [

    'client' => 'predis',

    'options' => [
        'prefix' => strtoupper(env('APP_NAME') . ':')
    ],

    'default' => [
        'host' => env('REDIS_HOST'),
        'password' => env('REDIS_PASSWORD'),
        'port' => env('REDIS_PORT'),
        'database' => env('REDIS_DB'),
        'read_write_timeout' => -1
    ],
    ...

这是中的redis连接配置 config/queue.php :

'redis' => [
        'driver' => 'redis',
        'connection' => 'default',
        'queue' => env('REDIS_QUEUE', 'default'),
        'retry_after' => 110
    ],

    'redis-long-run' => [
        'driver' => 'redis',
        'connection' => 'default',
        'queue' => env('REDIS_QUEUE', 'long-running-queue'),
        'retry_after' => 3620
    ],

如您所见,为同一物理redis服务器定义了两个连接。应用程序对两种不同类型的作业使用队列:
快速/短流程,如广播、通知或一些artisan命令调用。它们使用具有低超时设置的第一个连接配置。
在snowflake db(基于云的sql-like db)上查询大量数据和/或在solr服务器上更新/插入文档的长时间运行的进程。这些进程使用第二个连接配置,因为它们可能需要相当长的时间才能完成(对于从snowflake读取并写入solr的进程,通常大约需要20分钟)
该应用程序是一个供我的公司私人使用的商业webapp,负载相当小(每天排队的作业约为200个),但长时间运行的流程对业务至关重要:作业失败或重复运行是不可接受的。
这就是 config/horizon.php 文件:

'environments' => [
    'production' => [
        'supervisor-default' => [
            'connection' => 'redis',
            'queue' => ['live-rules', 'solr-cmd', 'default'],
            'balance' => 'simple',
            'processes' => 3,
            // must be lower than /config/queue.php > 'connections.redis'
            'timeout' => 90,
            'tries' => 3,
        ],
        'supervisor-long-run' => [
            'connection' => 'redis-long-run',
            'queue' => ['long-running-queue', 'solr-sync'],
            'balance' => 'simple',
            'processes' => 5,
            // must be lower than /config/queue.php > 'connections.redis-long-run'
            'timeout' => 3600,
            'tries' => 10,
        ],
    ],

    'staging' => [
    ...

初始问题

当我们在年初上线时,我们立即发现在长时间运行的队列连接上运行的作业有问题: Error while reading line from the server. [tcp://redis_host:6379] 错误开始左右跳跃。
这些转化成了作业被困在挂起状态,直到它们最终被标记为失败,尽管这些任务实际上已经成功了。
当时,应用程序的长时间运行进程仅限于snowflake select查询。
在阅读了laravel horizon的github问题以及so的主题上关于它的大量帖子并测试了这些建议之后,我们终于发现,罪魁祸首是我们的负载平衡器在90秒后关闭了连接。
redis的tcp keepalive默认配置参数是300秒,因此我们调整了haproxy的配置,使其以310秒的速度关闭,然后-poof!-,有一段时间一切正常。
这是haproxy目前应用程序的配置:

listen PROD-redis
    bind                    0.0.0.0:6379
    mode                    tcp
    option                  tcplog
    option                  tcp-check
    balance                 leastconn
    timeout connect         10s
    timeout client          310s
    timeout server          310s
    server 1        192.168.12.34:6379      check inter 5s rise 2 fall 3
    server 2        192.168.43.21:6379      check inter 5s rise 2 fall 3 backup

新问题(最初的重生?)

几个月后回来,应用程序已经进化了,我们现在有了一个任务,可以从snowflake中批量读取并生成solr update查询。solr客户端是solarium/solarium,我们使用addbuffered插件。
这在我们没有负载平衡的预生产环境中完美地工作。
所以下一步我们转到生产环境,redis连接问题又意外地出现了,只是这次我们正确地设置了haproxy。
通过监视redis中的密钥,我们可以看到这些作业确实被保留了,但在一段时间后会处于延迟状态,等待在达到作业超时后再次尝试。
这是一个真正的问题,因为我们最终会检查作业的最大尝试次数,直到它最终被标记为失败,运行它x次,因为它从未获得 complete 旗子,把不必要的压力放在环境和消耗资源,而事实上这项工作在第一次尝试时就成功了。
这是我们从haproxy的日志中得到的:
Jun 26 11:35:43 apache_host haproxy[215280]: 127.0.0.1:42660 [26/Jun/2020:11:29:02.454] PROD-redis PROD-redis/redis_host 1/0/401323 61 cD 27/16/15/15/0 0/0 Jun 26 11:37:18 apache_host haproxy[215280]: 127.0.0.1:54352 [26/Jun/2020:11:28:23.409] PROD-redis PROD-redis/redis_host 1/0/535191 3875 cD 24/15/14/14/0 0/0 这个 cD 根据haproxy的文件,部分是有趣的信息:
c : the client-side timeout expired while waiting for the client to send or receive data. D : the session was in the DATA phase. 像这样的日志还有很多,从日期上可以看出,在建立连接和关闭连接之间的延迟没有明显的规律。
在到达之前,我们有:
切换到redis版本5.0.3服务器:相同问题。
从等式中删除haproxy,并在客户机和redis之间建立直接连接:工作完美无瑕。
我有点不知所措,不知该如何解决这个问题。回到haproxy关于客户端超时的日志,我想知道客户端配置可能有什么问题,下一步应该尝试什么。
也许这里会有人来提个建议?谢谢你的阅读。

j5fpnvbx

j5fpnvbx1#

从laravel文档来看,最好使用phpredis客户端而不是predis。
predis已经被软件包的原作者抛弃,在未来的版本中可能会从laravel中删除。
简而言之,phpredis是一个用c编写的php模块。predis是用php编写的php库。这里描述了巨大的性能差异
顺便说一句,我们有类似的堆栈:laravel+horizon->haproxy->redis server。wу 有3台redis服务器(1台主服务器,2台从服务器)。和哨兵保持真正的主人。在我们从predis迁移到phpredis之前,redis也有类似的问题。在研究问题时,最好的答案是使用phpredis。
另外,我们刚刚把redis_客户端in.env从predis改为phpredis,一切正常。

相关问题