51

好的,所以我得到了这个完全罕见的负载平衡 PHP 网站的独特场景。令人遗憾的是 - 它以前不是负载平衡的。现在我们开始遇到问题了...

目前唯一的问题是 PHP 会话。自然一开始没有人想到这个问题,所以 PHP 会话配置保持默认。因此,两台服务器都有自己的少量会话文件存储,而将下一个请求抛出到另一台服务器的用户是不幸的,因为那没有他在第一个服务器上创建的会话。

现在,我一直在阅读有关如何解决这种情况的 PHP 手册。在那里我发现了session_set_save_handler(). (而且,巧合的是,这个话题关于 SO) 整洁。除了我必须在网站的所有页面中调用这个函数。未来页面的开发人员也必须记住一直调用它。感觉有点笨拙,更不用说可能违反了十几个最佳编码实践。如果我可以翻转一些全局配置选项会更好,然后——会话都神奇地存储在数据库或内存缓存或其他东西中。

关于如何做到这一点的任何想法?


补充:澄清 - 我希望这是标准解决方案的标准情况。仅供参考 - 我有一个可用的 MySQL 数据库。肯定有一些现成的代码可以解决这个问题吗?当然,我可以编写自己的会话保存内容,Gregauto_prepend指出的选项似乎很有希望——但这感觉就像重新发明轮子一样。:P
补充2:负载均衡是基于DNS的。我不确定这是如何工作的,但我想它应该是这样的。
补充 3:好的,我看到一种解决方案是使用auto_prepend选项在每个脚本中插入调用session_set_save_handler()并编写我自己的数据库持久化器,也许会调用调用以memcached获得更好的性能。很公平。

还有一些方法可以避免我自己编写所有这些代码吗?就像一些著名且经过良好测试的 PHP 插件一样?

很久很久以后添加:这就是我最终采用的方式:如何在 PHP + MySQL 中正确实现自定义会话持久性?

此外,我只是在所有页面中手动包含会话处理程序。

4

10 回答 10

36

您可以设置 PHP 来处理数据库中的会话,因此您的所有服务器共享相同的会话信息,因为所有服务器都使用相同的数据库。

一个很好的教程可以在这里找到

于 2009-06-15T09:04:46.993 回答
22

我们处理这个问题的方式是通过 memcached。只需更改 php.ini,如下所示:

session.save_handler = memcache
session.save_path = "tcp://path.to.memcached.server:11211"

我们使用 AWS ElastiCache,因此服务器路径是一个域,但我相信本地 memcached 也类似。

此方法不需要任何应用程序代码更改。

于 2012-10-24T15:20:12.680 回答
10

您没有提到您使用什么技术进行负载平衡(软件、硬件等);但无论如何,解决您的问题的方法是在负载均衡器上使用“粘性会话”。

总而言之,这意味着当来自“新”访问者的第一个请求进来时,他们会从集群中分配到一个特定的服务器:所有未来在其会话生命周期内的请求都会被定向到该服务器。在实践中,这意味着为在单个服务器上工作而编写的应用程序可以升级到零/很少代码更改的平衡环境。

如果您使用的是硬件平衡器,例如 Radware 设备,则粘性会话将配置为集群设置的一部分。硬件设备通常会给你更细粒度的控制:比如新用户被分配到哪台服务器(他们可以检查健康状态等并选择最健康/利用率最低的服务器),以及更多地控制服务器时发生的事情失败并退出集群。硬件平衡器的缺点是成本 - 但恕我直言,它们是值得的。

至于软件平衡器,这取决于您使用的是什么。对于 Apache,mod_proxy 上有 stickysession 属性 - 并且通过 google 有大量文章可以使用 php 会话(例如


编辑:从原始问题之后发布的其他评论来看,听起来您的“平衡”是通过循环 DNS 完成的,因此上述内容可能不适用。我将避免进一步评论并开始对循环 dns 发起攻击。

于 2009-06-15T08:48:58.480 回答
4

最简单的做法是将负载均衡器配置为始终将相同的会话发送到同一台服务器。

如果您仍然想使用,session_set_save_handler那么可以看看 auto_prepend。

于 2009-06-15T08:10:14.877 回答
4

如果您有时间并且仍然想查看更多解决方案,请查看 http://redis4you.com/articles.php?id=01 ..

使用 redis 你是容错的。从我的角度来看,由于这种健壮性,它可能比 memcache 解决方案更好。

于 2013-07-13T14:06:50.483 回答
3

如果您使用 php 会话,您可以与 NFS 共享 /tmp 目录,我认为会话存储在集群中的所有服务器之间。这样你就不需要数据库了。

已编辑:您还可以使用 memcachedb 之类的外部服务(持久且快速)并将会话信息存储在 memcachedb 索引中,并使用内容的哈希甚至会话 ID 来识别它。

于 2009-06-15T12:02:35.177 回答
2

当我们遇到这种情况时,我们实现了一些位于公共标头中的代码。

基本上对于每个页面,我们都会检查我们是否知道会话 ID。如果我们不检查我们是否处于您描述的情况,通过检查我们是否在 DB 中存储了会话数据。否则我们只是开始一个新会话。

显然,这需要将所有相关数据复制到数据库中,但是如果您将会话数据封装在单独的类中,那么它可以正常工作。

于 2009-06-15T08:27:37.737 回答
2

您也可以尝试使用 memcache 作为会话处理程序

于 2009-06-15T08:51:34.810 回答
2

可能为时已晚,但请查看:http ://www.pureftpd.org/project/sharedance

Sharedance 是一种高性能服务器,可将临时密钥/数据对集中在远程主机上,无需 SQL 数据库的开销和复杂性。

它主要设计用于在 Web 服务器池之间共享缓存和会话。通过简单的 PHP API 访问共享服务器是微不足道的,它与 PHP 4 和 PHP 5 会话处理程序的期望兼容。

于 2013-12-03T10:29:30.593 回答
1

当涉及负载平衡集群中的 php 会话处理时,最好有粘性会话。为此,请询问维护负载均衡器的数据中心网络以启用粘性会话。一旦启用,您将无需担心 php 端的会话

于 2017-01-13T08:20:10.520 回答