无法关闭会话警报

前言

早上好/晚上好。
我是Una,是Ancar股份有限公司的Web工程师。
这次我将担任「株式会Ancar ~Advent Calendar 2019~」的第八天任务。

我們的宗旨是提供安心安全的移動體驗。

    • 中古車の個人間売買をオンラインで行うサービス

全国の中古車からお買い得な車を検索・比較できるサービス
を展開しております。

在本文中,我們將分享在服務運營期間出現的警告處理方法。

总结为3条简要描述

PHP Warning: SessionHandler::read(): Unable to clear session lock recordが3件/日ぐらい発生
どうやらセッションロック周りが怪しい → n度修正 → 鳴り止まないアラート
memcachedからredisを移行させた結果、直った(嬉しい

每天有3个会议提醒。

mackerelというサーバー管理システムから、頻繁にアラートがあがるようになった。
内容はPHP Warning: SessionHandler::read(): Unable to clear session lock record
アラートが増加している上に、SEOにも影響が出ている可能性が高まってきたため、対処に動いた。

那个时候的环境

    • PHP7.1

 

    • memcached3.0.3(elasticache)

 

    nginx/1.10

这是由于会话锁定吗?

经过向谷歌先生询问警报内容后,发现会话锁定存在可疑情况。

为了防止并发写入,会对会话数据进行锁定,因此在某一时刻只能有一个脚本来处理会话。请参考链接:https://www.php.net/manual/ja/function.session-write-close.php

换言之,我推测在会话已经被锁定的情况下,试图再次向该会话写入会导致错误。

image.png

我充满信心地为/etc/php/7.1/fpm/conf.d/25-memcached.ini中的sess_lock设置了与测试服务器相同的时间。告别了警报…(我也曾有过这样的时期).

结果,发生了警报…
从这里开始,我与警报之间的激烈战斗(一个丧尸游戏)开始了。

只依靠摇滚时间还不足够吗?

在之前的戰鬥中,有點過於急躁。下定決心進行牢固地佔領,開始深入研究問題。參考了這些問題,來完善設定。

session.lazy_write = Off;
memcached.sess_lock_wait_min = 100;
memcached.sess_lock_wait_max = 150;
memcached.sess_lock_retries = 30;
memcached.sess_lock_expire = 45;

但是,警报声响起得很欢快。
相反,它稍微增多了一些。
原来如此,难道没有怜悯之心吗…

当我开始深入研究这个问题时,我意识到这个问题其实比我想象的更为严重根深蒂固。
修复的方法有些情况是可以通过之前的修正来解决的,但也有相反的情况。
在PHP7.1以前和memcached搭配使用时,这个问题频繁发生,很可能是由于PHP的版本问题所导致的。

通过多次更改设置的实际经验,我深刻感受到,对付这令人厌恶的警报并不是一个合适的方法。
以下是被认为是有效的选项。

    • PHP7.2以上

cf: https://github.com/php-memcached-dev/php-memcached/issues/269#issuecomment-519886598

redisへ移行

cf: https://github.com/magento/magento2/issues/5319#issuecomment-265595804

迁移到Redis

考虑到对服务的影响,PHP的更新工作风险与回报不成正比,因此决定放弃。
结果,决定改变路线,转向redis迁移。
同时,恶贯满盈的对手升级为宿敌,呼啸先生成为了一名敌人。

转型的关切

    • redis移行で問題が本当に解決するのか

打ち手: redisにして解決したソースあり
打ち手: 本番2号機サーバーで確認

移行後にmemcachedに戻れるのか

打ち手: エンドポイントをredisに向けて対応(memcachedの設定を上書き)
打ち手: テスト環境で双方向(memcached ↔ redis)の行ききをし、後戻りできることを確認

redis移行で他に問題が起きないのか

打ち手: テスト環境で確認
打ち手: 本番2号機サーバーで検証

影響範囲が大きいため、打ち手と手順を考えて実行した。
1. テスト環境で実装した後、動作確認。
2. 本番環境の冗長構成のサーバーを間借りして、動作確認。
3. 本番に完全移行。

Redis 迁移的步骤

很遗憾,ElastiCache不支持自动将Memcached从Redis迁移至Redis。

    1. 在Elasticache中创建一个Redis实例

 

    1. 将Redis端口(6379)添加到ELB的安全组

 

    1. 在服务器内部执行pecl install redis命令

 

    1. 在/etc/php/7.1/fpm/php.ini文件中添加extension=redis.so

 

    在/etc/php/7.1/fpm/php.ini文件中添加session.save_handler和session.save_path
session.save_handler = redis
session.save_path = ****.cache.amazonaws.com:6379
image.png

静默的警报

在解决之前的担忧后,我们进行了Redis的完全迁移,数天过去了。
然而,宿敌仍未现身…
那个每隔数个小时就会冒出来的家伙,居然数天都没有露面…
因此,我要宣布胜利了。

闲话

在监视Alert先生时,我使用Apache Bench(以下简称为ab)对Memcached和Redis进行了负载测试。
由于负载测试的结果会因测试环境而有所不同,因此需要在一些不同的地方进行测试。
此外,据说AWS不再需要事先申请渗透测试。

苹果电脑自带ab,但如果在服务器上使用,则需要安装。
sudo apt install apache2-utils //仅安装ab软件包

进行ab负载测试

Redis比较快…!!

1秒間のリクエスト処理比較memcachedredisab -n 1000 -c 100 //10回×100人41.93/sec41.53/secab -n 10000 -c 100 //100回×100人42.79/sec41.65/sec

估計/猜測

尽管对memcached和redis施加了类似于自我拒绝服务攻击的负载,但未引发警报。
由此可知,警报不是由于会话增加而产生的。
这不是由于总数的增加而引发的,而是由于无法写入会话。
网站的页面访问量和会话警报的增加看起来在时间上有关联,但根本原因尚未解明。