Laravel 会话使用 Memcached 踩到的坑

前言

此文章相当于开发记录,希望能帮助遇到同样问题的同学,或在看了此篇文章后能避免犯同样的错误。

问题描述

之前项目开发时,SESSION_DRIVER 使用的是 redis,后来为了分离逻辑,将其修改成 memcached

这时问题来了,配置修改后,用户无法正常登陆,表现为登陆成功后一刷新页面,又显示为 未登录 状态。

定位问题

针对此问题,当时专门做了几个排查步骤:

  1. 检查 memcached 服务是否启动;
  2. 检查 memcached 是否能正常存储数据;
  3. 检查 memcached 有无被其他设置覆盖;

结果上面的步骤均正常。这时突然想到会不会是 过期时间 设置有问题?

打开 config/session.php 文件一看果然如此:

file

之前开发的小伙伴为了能长久保持 Session,lifetime 值设置为了 525600 (即 1 年),而 memcached 默认的过期时间则 不能大于 30 天

最终将 lifetime 的值修改为默认值 43200(1440 * 30),Bug Fixed!:beers: :beers:

附录

Memcache maximum key expiration time

monkey
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 4

@Summer 是的, 再给 session 分配一个 redis 数据库就行了。

    'redis' => [

        'cluster' => false,

        'default' => [
            'host' => env('REDIS_HOST', 'localhost'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', 6379),
            'database' => 0,
        ],

        'session' => [
            'host' => env('REDIS_HOST', 'localhost'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', 6379),
            'database' => 1,
        ]

    ],

将来如果项目大了,可以专门给弄台服务器跑 session 的 redis ,多台 web 服务器连接同个 session 服务器,这样分布式情况下能保证负载均衡时,访问任意 web 服务器都能够正确的获取唯一的 session 信息。如果项目更大了,那么 session 服务器也可以分布式。

个人推荐以后就用 redis 吧,其实... memcached 已过时了 :smile:

http://blog.nosqlfan.com/html/3729.html

7年前 评论

还真不知道memcached有30天的限制:smile: 。

有个问题,为什么要说 为了分离逻辑 换到 memcached 呢?

我认为 redis兼顾持久化存储,应用起来比 memcached 更可靠。

记得之前有个案例日本最大社交网站因为 memcached 服务器因为一个BUG崩溃,数据全部丢失,重启后,memcached需要写入大量缓存内容(因为重启之后内存里的数据就没了,而memcached是只存储在内存)导致服务器压力太大,一直崩溃。

Session 是用户的登录信息,是需要存储一定时间的。如果使用memcached的话,当服务器重启(宕机、更新等),用户就需要重新登录,因为所有的 Session信息已丢失。如果存储到 redis,就算服务器重启也没什么关系,并且兼顾了存到内存的存取效率,还是相当靠谱的。

7年前 评论
Summer

@zhuzhichao 三天两头 PHPHub 需要重新登录的,就是 @monkey 整的。

@monkey 30 天会话保持时间太少了,数据库并太消耗了,还是得使用 redis,我刚刚找了一些资料,你瞧瞧哈:

file

7年前 评论

@Summer 是的, 再给 session 分配一个 redis 数据库就行了。

    'redis' => [

        'cluster' => false,

        'default' => [
            'host' => env('REDIS_HOST', 'localhost'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', 6379),
            'database' => 0,
        ],

        'session' => [
            'host' => env('REDIS_HOST', 'localhost'),
            'password' => env('REDIS_PASSWORD', null),
            'port' => env('REDIS_PORT', 6379),
            'database' => 1,
        ]

    ],

将来如果项目大了,可以专门给弄台服务器跑 session 的 redis ,多台 web 服务器连接同个 session 服务器,这样分布式情况下能保证负载均衡时,访问任意 web 服务器都能够正确的获取唯一的 session 信息。如果项目更大了,那么 session 服务器也可以分布式。

个人推荐以后就用 redis 吧,其实... memcached 已过时了 :smile:

http://blog.nosqlfan.com/html/3729.html

7年前 评论
Summer

最终的解决方案:https://phphub.org/topics/2466

谢谢 @zhuzhichao 的指点 :kissing_closed_eyes:

7年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!