【问题标题】:Storing userdata in $_SESSION vs. repeated DB accesses将用户数据存储在 $_SESSION 中与重复的数据库访问
【发布时间】:2013-01-14 22:30:47
【问题描述】:

在后续的页面请求中需要从 (MySQL) 数据库中读取的某些用户数据,比如用户名或某些首选项。

将此数据存储在 $_SESSION 变量中以节省数据库查找是否有益?

我们正在谈论(可能)很多用户。我想存储在 $_SESSION 中会增加 RAM 的使用量(非常少的数量乘以非常多的用户),而在每个页面上一次又一次地请求相同数据时访问数据库应该会增加磁盘活动。

【问题讨论】:

  • 会话数据默认存储在磁盘上。虽然它正在分配来自数据库的负载,但您仍然会有一些磁盘 io,其中会话数据存储在该位置。您可能想考虑使用 memcached 作为不错的选择。
  • 数据库可能不会(再次)访问磁盘,因为记录已经在内存中。
  • @Karoly:所以最好不要在 $_SESSION 中存储已经保存在数据库中的任何内容,只是反复从数据库中读取,希望它已经在内存中?
  • 您必须对其进行测试,但是如果它是单个查询,那么您不会获得太多...如果是几个查询,那么值得将其缓存在 K-V 存储中,但是您如果值发生变化,必须在应用程序中构建逻辑以更新缓存...

标签: php mysql session


【解决方案1】:

您的问题具有讽刺意味的是,对于大多数系统而言,一旦获得大量用户,您就需要找到一种方法将会话从默认的磁盘存储中取出并放入单独的持久层(即数据库、内存缓存等)。这是因为在某些时候您需要多个应用程序服务器,而不必在应用程序服务器本身上维护状态通常要容易得多。

许多大型系统使用内存缓存(memcached 或类似的)来进行会话持久性,因为它可以为多个前端服务器提供一个通用的持久性层,并且不需要长时间的持久性(磁盘存储) 的数据。

设计良好的数据库表或其他基于磁盘的键值存储也可以成功使用,尽管它们的性能可能不如内存存储。但是,它们的运行成本可能更低,具体取决于您希望使用每个会话密钥存储多少数据(在 RAM 中保存大量数据通常比在磁盘上存储更昂贵)。

了解会话数据的大小(平均大小和最大大小)、您希望支持的并发会话数以及需要访问会话数据的频率对于帮助您确定解决方案很重要最适合您的情况。

【讨论】:

  • 哦,哇。这……比我预期的要复杂得多。不过还是谢谢!
  • @Marcos 其实并没有那么复杂。我要说的第一件事是粗略估计所需的存储大小。您可以确定这是在计算 average_session_storage_size (bytes) x number_of_sessions_utilized (#/per second) x session_expiration_limit (seconds)。这将产生您需要支持的字节大小。如果这个数字相对较小(
【解决方案2】:

您可以为 PHP 中的会话数据使用多个存储后端。默认情况下,它保存到文件中。一个文件一个会话。您还可以通过实现自己的session save handler 将数据库用作会话后端或任何您不想要的东西

如果您希望您的应用程序具有最大的可扩展性,我会在文件系统上使用会话。想象一下,您有一个包含多个 Web 服务器的设置,所有这些服务器都将您的站点作为一个场来提供服务。在文件系统上使用会话时,必须为每个请求将用户重定向到同一服务器,因为会话数据仅在该服务器文件系统上可用。如果您不在文件系统上使用会话,则用于请求的服务器无关紧要。这使得负载平衡更加容易。

我建议不要在文件系统上使用会话

  • 使用 cookie
  • 在多个请求中使用请求变量

或(如果数据对安全至关重要)

  • 使用带有数据库保存处理程序的会话。因此,从数据库(或集群)读取数据的每个网络服务器都可以使用数据。

【讨论】:

  • 这两个都不安全(用户可以发送任意数据),所以用例非常有限……
【解决方案3】:

使用会话有一个主要缺点:如果用户都尝试启动会话以访问数据,则您无法为用户提供并发请求。这是因为 PHP 会在脚本启动会话后锁定会话,以防止数据被另一个脚本覆盖。使用会话数据时通常的想法是,在您调用session_start() 之后,数据在$_SESSION 中可用,并且在脚本结束后将被写回存储。在此之前,您可以愉快地随意读写会话数组。 PHP 确保这不会通过锁定数据来破坏或覆盖数据。

如果您想创建一个对服务器进行大量 Ajax 调用的 Web2.0 站点,锁定会话会降低性能,因为需要会话的每个请求都将连续执行。如果可以避免使用会话,将有利于用户感知性能。

有一些技巧可以解决这个问题:

  1. 您可以尝试通过调用session_write_close() 尽快释放锁定,但是您必须处理在此调用之后无法写入会话的问题。
  2. 如果您知道某些脚本调用只会从会话中读取,您可以尝试实现只读取会话数据而不调用session_start() 的代码,并完全避免锁定。
  3. 如果 I/O 存在问题,使用 Memcache 服务器进行存储可能会提高性能,但不能帮助您解决锁定问题。
  4. 请注意,数据库也存在这种锁定问题,它存储在任何表中的所有数据。如果您的数据库存储引擎选择不明智(例如 MyISAM 而不是 InnoDB),您将失去更多的性能,而不是避免会话。

如果您现在根本没有任何性能问题,那么所有这些讨论都是没有意义的。做最符合您意图的事情。无论您稍后会遇到什么性能问题,我们今天都无法知道,而试图避免它们将是过早的优化(这是邪恶的根源)。

始终遵循优化的第一条规则:衡量它,看看是否有更改改进它。

【讨论】:

  • 感谢您的意见。会试一试!
猜你喜欢
  • 2012-01-18
  • 2012-03-03
  • 2011-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-08
相关资源
最近更新 更多