使用nosql缓存session数据

场景需求

使用PHP搭建网站或API Server时,常常需要用到$_SESSION['user']等全局变量获取到用户的状态及数据。若服务器已经安装memcached/redis,则可通过相关的配置,将session文件缓存到memacached/redis服务器,降低硬盘IO,提升网站的性能。

配置nosql缓存Session

可以通过命令行配置,修改php.ini,将session.save_handler修改为memcached/redis,同时,将原有的/tmp路径更改为服务器memcached服务的ip及端口。

1
2
session.save_handler = memcached
session.save_path = "127.0.0.1:11211"

还可以通过session.gc_maxlifetime配置缓存的时间。

1
session.gc_maxlifetime = 1440

也可直接使用Redis储存Session数据,

1
2
session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379"

多服务器

当我们的服务使用一台服务器已经无法满足的时候,并开始集群化部署,同一个用户可能会访问到不同服务器,这时候就需要多服务器共享session,虽然使用一台memcached也足以应付,但若需要使用memcached集群,则可进一步配置。
可以使用,将服务器集群隔开,并使用不同额参数来配置各个memcached服务器的比重等等,可参考Memcached::addServer

1
session.save_path = "127.0.0.1:11211?weight=67,127.0.0.2:11211?weight=33"

SASL认证

一方面,若使用第三方的服务,则需要账号密码鉴权,另一方面,服务器较多或出于安全性考虑,也可以在php.ini中配置帐号密码。

1
2
3
4
5
6
[memcached]
memcached.use_sasl = On
memcached.sess_binary = On
memcached.sess_sasl_username = “your_ocs_name”
memcached.sess_sasl_password = “your_ocs_password”
memcached.sess_locking = Off

解决跨域问题

对于大型的BS网站,通常按不同服务器运行不同功能模块及子系统,分别使用不同的域名或者同样的域名,比如yatesun.comwww.yatesun.com等等。默认的情形下,客户端访问不同服务器或同一台服务器的不同hosts(domain),服务器会为不同的客户端生成不同的SESSION_ID,用于识别每一位用户。对于同一个客户端,SESSION_ID在有效期内是不会变的。对于不同的服务器,通过使用Memcached已经解决了Session的保存问题。那么对于不同域名之间的跨域,同样可以在php.ini的配置中进行配置,
解决跨域问题

1
session.cookie_domain = ".yatesun.com"

或针对每个应用进行独立配置,

1
ini_set('session.cookie_domain', '.yatesun.com');

配置成功后,*.yatesun.comyatesun.com就均可访问此cookie,并通过memcached集群获取到SESSION_ID对应的用户数据,基本解决跨域问题。

可能存在的问题

由于Memcached使用LRU(Least Recently Used)算法回收缓存,LRU算法是针对每个slab类执行,而不是针对整个Memcached,核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。最近最少使用的数据有可能被回收,这意味着有可能用户在某个时间点登录了,但又长期不在线,隔了较长一段时间之后,可能他的session已经被回收了。
当然这仅仅是一种可能性,若从可靠性来讲,使用Redis将是一种更好的选择。
可参考Memcached作者两篇文章Sessions in MemcachedCache your sessions,还有一篇Memcached的流程图

更多配置

更多的配置还可以参考Memcached运行时配置