memcached

时间:2015-06-11 12:31:09

标签: php session authentication zend-framework2 memcached

在我们的Intranet应用程序中,我们使用SSO(单点登录)登录,而客户端和auth源应用程序上的会话都存储在memcached中。

会话设置为在垃圾收集器可能将其视为删除之前的12小时。这两个应用程序都是使用ZF2编写的。

不幸的是,问题是,在一段时间后(我没有确切的值),浏览器会丢失导致重定向到auth origin的会话,其中会话仍处于活动状态,因此用户被重定向返回客户端并刷新浏览器会话。如果用户没有未保存的工作,这不是什么大问题,因为这两个重定向在1秒内发生,用户甚至可能不会注意到它们。

但是当用户有未保存的工作时,这确实是一件大事,即使尝试保存它也会导致重定向,工作也就消失了。

以下是Bootstrap.php中会话的配置:

class Module
{
    public function onBootstrap(MvcEvent $e)
    {
        // ...
        $serviceManager      = $e->getApplication()->getServiceManager();
        $sessionManager      = $serviceManager->get('session_manager_memcached');
        $sessionManager->start();
        Container::setDefaultManager($sessionManager);
        // ...
    }

    public function getServiceConfig()
    {
        return array(
            'factories' => array(
                // ...
                'session_manager_memcached' => function ($sm) {
                    $systemConfig = $sm->get('config');
                    $config = new SessionConfig;
                    $config->setOptions(array(
                        'phpSaveHandler' => 'memcache',
                        'savePath' => 'tcp://localhost:11211?timeout=1&retry_interval=15&persistent=1',
                        'cookie_httponly' => true,
                        'use_only_cookies' => true,
                        'cookie_lifetime' => 0,
                        'gc_maxlifetime' => 43200, // 12h
                        'remember_me_seconds' => 43200 // 12h
                    ));
                    return new SessionManager($config);
                },
                // ...
        );
    }
}

身份验证服务定义为

            'authService' => function ($sm) {
                $authService = new \Zend\Authentication\AuthenticationService;
                $authService->setStorage(new \Zend\Authentication\Storage\Session('user_login'));
                return $authService;
            },
  • 会话存储使用相同的memcached会话管理器。

然后在应用程序中的任何地方都需要检索或设置会话值我只需使用\Zend\Session\Container这样:

$sessionContainer = new \Zend\Session\Container('ClientXYZ');
$sessionContainer['key1'] = $val1;
// or
$val2 = $sessionContainer['key2'];

在会话中使用来自auth origin的PHPSESSID的令牌,在活动会话中请求SSO。在这个问题中描述这个很复杂。

此外,身份验证服务还使用相同的设置在memcached会话中存储用户身份(具有ACL的角色)。显然,现在这是造成混乱的地方。显然,身份验证服务的会话存储过早地超时导致ACL不检索用户身份以检查导致SSO注销序列(但由于用户没有真正注销,SSO如上所述重新定向用户)。 p>

我不确定我(也可以)在这里分享多少代码,也许您可​​以立即引导我解决问题,或者只是问我一些问题。经过数小时的调试并试图找出问题后,我现在很无助。

在某个地方,我已经读过,当会话 cookie 的大小达到1MB时,memcached会擦掉内存 - 可能是这种情况吗?对于用户身份,我们只保存一般用户信息和角色阵列,我猜这可能是最大的。高达几kb ......

编辑1:为了驳回所有猜测并节省您的时间,这里有一些事实(为了留意):

  • 仅使用memcached
  • cookies仅用于在浏览器和服务器之间传输PHPSESSID,它的值是存储数据的memcached中内存块的关键
  • 客户端和SSO auth应用程序在一台服务器上运行(无论是集成,登台还是实时环境,还只是一台服务器)
  • 客户端应用程序上的
  • 会话随机关闭,导致其重定向到SSO auth应用程序,但此处会话仍处于活动状态,因此用户被重定向回客户端应用程序,获取新会话并且用户保持登录状态
  • 这应该忽略有关擦除或重新启动memcached的讨论
  • 对telneted memcached的观察直接显示两个数据块(对于客户端和auth应用程序)几乎同时使用相同的ttl建立

我将在PHP中实现一些die,在JS部分中实现return以捕获会话被认为已经消失的时刻,并进一步检查浏览器cookie,memcached数据等。会更新你(除非有人提供解释和解决方案)。

3 个答案:

答案 0 :(得分:1)

Memcached& gc_maxlifetime

使用memcached作为session.save_handler时,会话的垃圾收集将

因为Memcached使用TTL(生存时间)值,所以不需要垃圾回收。没有足够长的时间达到TTL年龄的条目将被视为“新鲜”并将被使用。之后它将被视为“陈旧”,并且将被再次使用。最终Memcached将释放条目使用的内存,但这与PHP的会话垃圾收集无关。

实际上,在这种情况下实际使用的唯一session.gc_设置是session.gc_maxlifetime,它将作为TTL传递给Memcached。

简而言之:在您的情况下,垃圾收集不是问题。

Memcached& Cronjobs

当您使用Memcached作为会话的存储时,操作系统提供的任何手动清理磁盘上的会话文件夹(如Ubuntu)的cronjobs将无效。 Memcached是内存存储,而不是磁盘存储。

简而言之:像你这样的cronjobs不是你的问题。

应用程序问题,而不是SSO

您声明SSO服务器/授权与SSO客户端(应用程序本身)在同一台计算机上,使用相同的Web服务器/ PHP配置,并使用相同的Memcached实例。

这让我相信我们必须在应用程序中搜索会话管理的方式,因为这是SSO权限和客户端之间的唯一区别。换句话说:我们需要深入了解Zend \ Session。

免责声明:我专业从事过几个Zend Framework 1应用程序,但没有在任何Zend Framework 2应用程序上工作。所以我在这里失明:)

配置

我在您的配置中注意到的一件事是您已将cookie_lifetime设置为0。这实际上意味着“直到浏览器关闭”。这与remember_me_seconds设置为12小时并不合理,因为很多人会在此之前关闭浏览器。

我建议您将cookie_lifetime设置为12小时。

另请注意,remember_me_seconds仅在实际使用“记住我”功能时使用。换句话说:如果调用Zend\Session\SessionManager::rememberMe()

替代实施

看看你使用Memcached作为会话存储实现的方式,以及我在这个主题上可以找到的内容,我会说你做了一些与“首选方式”不同的东西。

关于此主题的大多数资源建议使用Zend\Session\SaveHandler\Cachedocapi)作为保存处理程序,这使您能够使用Zend\Cache\Storage\Adapter\Memcached({{3 },doc)。这使您可以更好地控制正在发生的事情,因为它不依赖于有限的memcached会话保存处理程序。

我建议你试试这个实现。如果它不能立即解决您的问题,则至少需要更多资源才能找到该主题。你找到解决方案的机会会更好恕我直言。

答案 1 :(得分:1)

 package main

 import "fmt"

 func main() {
 k := 6
 switch k {
    case 4: fmt.Println("was <= 4"); fallthrough;
    case 5: fmt.Println("was <= 5"); fallthrough;
    case 6: fmt.Println("was <= 6"); fallthrough;
    case 7: fmt.Println("was <= 7"); fallthrough;
    case 8: fmt.Println("was <= 8"); fallthrough;
    default: fmt.Println("default case") 
    }
}

这是我用来为X用户创建cookie的函数。无论是否有重定向或用户是否关闭了浏览器,cookie都会存在3个小时。它还在那里。只需在Module.php中的onBootstrap()方法中调用此函数。

在记录时,我使用ZF2 AuthenticationService和Container来存储和检索用户数据。

我建议您安装这些模块以便于调试。 https://github.com/zendframework/ZendDeveloperTools https://github.com/samsonasik/SanSessionToolbar/

答案 2 :(得分:0)

这个答案可能无法立即解决memcache问题的原因,但由于memcache的不可靠性,我建议在一些持久存储中备份memcached数据。 记忆数据将帮助您提高应用程序的性能,但它不是故障安全的。

也许你可以在AuthenticationService实例中建立一个后备(持久)存储。然后首先尝试从memcache中获取身份验证数据,如果没有找到任何内容,则检查持久存储中是否有可用的内容。

这至少可以解决所有意外的memcache丢失问题。