【问题标题】:Storing all user activity as session values and saving session values at the end of session将所有用户活动存储为会话值并在会话结束时保存会话值
【发布时间】:2011-11-26 08:35:25
【问题描述】:

通常,我会通过在 php 中对每个页面加载执行查询来保存所有用户活动、页面视图和所有值。

  • 现在我正在考虑将所有这些存储为会话值和 在会话结束时执行查询。但是,我不知道如何在 php 中处理这个“会话结束”事件。

我想到了一个后台进程,它在会话超时之前存储所有会话值,但我对 php 中的多线程方法一无所知,即使我听说有一些规避是可能的。

  • 我想确定用户是否在没有用户的情况下处于非活动状态 触发(如页面加载)并将所有会话值保存在 会话结束,在超时之前。

这样可以节省数据库引擎的一些工作量,如下所示: 一个用户查看了很多页面,我增加了会话中的值,而不是执行类似的查询

update pageviews set numberofviews=numberofviews+1

在每个页面加载时。

  • 问题是这样的:“如何在 php 中处理会话结束事件 没有用户活动?”

对实际问题的解决方案也表示赞赏。无论与粗体问题的相关性如何。 (我还没有开始编写代码,我的问题不是关于错误修复。)

可能的解决方案:

我找到了php session handler functioon,但文档没有说明它是否可以为回调参数设置空参数?

如果我为 $callback 参数输入空参数,我会失去标准功能吗?

我只想更改会话 $destroy 事件。我现在需要这方面的帮助。

相关帖子: RP1

【问题讨论】:

  • 这个问题与多线程有什么关系。
  • apc、memcache、redis 中的工具都不符合您的要求?

标签: php events session event-handling


【解决方案1】:

您不能真正使用 session_destroy 处理程序,因为它仅在您显式调用 session_destroy 时才会调用,如果用户只是关闭浏览器并结束会话,则不会发生这种情况。由于在这种情况下无法捕获会话结束“事件”,因此您必须改为进行某种定期检查以查看会话是否在给定时间段内处于空闲状态。最简单的方法是在您的会话中创建一个包含上次访问时间的字段,然后创建一个脚本,该脚本会定期(通过 cron 或触发您的 PHP 脚本中的某些其他功能)检查该字段的所有活动会话,并且,对于时间戳早于 xx 秒的任何时间戳,请运行更新查询。

请注意,为了使用存储在文件系统上的标准 PHP 会话来执行此操作,您必须实际打开文件并直接解析它们。另一种方法是将会话存储在数据库中,但这可能不是您想要做的,因为您正试图减少数据库上的负载。

另一种不太需要开发的可能性是:

  1. 为您的会话添加上次访问的时间戳
  2. 每次更新会话时检查时间戳
  3. 如果时间戳早于 xx 秒,则在数据库上运行更新查询并将时间戳设置为当前时间。

这样,您只需经常更新数据库,而不是每次加载页面。当然,这种方法的缺点是除非会话中的最后一个活动与调用更新函数的时间间隔完全对应,否则您可能不会在数据库中存储最新的会话信息。

【讨论】:

    【解决方案2】:

    这不是创建会话的目的,因此仅靠会话机制无法实现您想要实现的目标。

    使用标准 PHP 会话,您的选择会受到一定限制,并且取决于会话存储:

    1. 默认情况下,会话存储在文件中。如果您禁用会话垃圾收集,您可以运行一个 cron 作业,该作业将解析早于您定义的时间的会话文件。它并不完美,但到目前为止是最简单的。文件会话也很糟糕 - 写入每个请求。
    2. Memcached 中的会话。由于没有获取早于 x 的记录的好方法,而且 Memcached 只会在数据过期时删除数据这一事实,因此无法在此处完成。
    3. 数据库中的会话 - 您已经对每个请求进行了更新。

    因此,您对标准会话的选择最多是有限的。我的建议:用您自己的会话替换标准会话,但这意味着您将不再通过 $_SESSION 访问会话,并且需要您重写大量代码。

    我已将常规会话替换为将会话数据存储在 APC/Memcached 和 DB 中的单例。仅当我请求会话数据 (Session::persistentStore($key,$value)) 或在处理请求期间 APC/Memcached 存储的会话数据表明它没有被写入足够长的时间时,会话数据才会保存在 DB 中。这极大地限制了写入次数。 使用此替换,您只需从数据库端强制会话保存:从数据库获取 x 分钟内未更新的会话的会话 ID,从 APC/Memcached 获取每个会话的信息,如果那里没有更新信息或者(表示会话即将结束)将其保存到数据库。

    【讨论】:

      【解决方案3】:

      这里只是一个疯狂的想法,您可以触发一个 http 请求,以将会话数据保存在从 javascript 卸载的窗口中。问题是浏览器通常会在页面关闭后停止请求,所以这个请求甚至可能不会到达服务器,但我想这值得一试。

      【讨论】:

        【解决方案4】:

        尽管有一些变通方法,但您可以找到解决此问题的每个解决方案都比在每个请求中记录每个用户活动效率低。

        【讨论】:

          【解决方案5】:

          你想解决什么问题?我不明白为什么您不会在每次请求时都向数据库触发更新查询。它所花费的时间不应超过 0,0001 秒。

          我绝对会去更新每个请求。它是 1 行代码,不会对数据库造成任何过度负载,而且效率更高。

          您提出的方法很难测试,会产生不必要的负载,甚至可能会产生全局状态。您可以通过采用传统解决方案来防止所有这些。会话在确定何时“结束”时是一个(...)。

          【讨论】:

          • 在asp.net中很容易做到
          • 更新 = 写操作。硬盘驱动器有 70-150 iops,当负载增加时,您会开始注意到这一点。
          • 执行每个请求都需要大量查询,这不会是最重的。
          【解决方案6】:

          我想到了一个存储所有会话值的后台进程 就在会话超时之前,但我对此一无所知 php中的多线程方法,尽管我听说过一些 规避是可能的。

          如果您相当容易地使用基于数据库的会话,则可以这样做。

          1. 不需要多线程
          2. 编写一个每分钟 / 5 分钟运行一次的 cron 作业
            • 选择所有即将过期的记录
            • 将它们保存到其他表中

          关键是使用 cron 作业,而不是尝试在 http 请求中处理过期事件

          【讨论】:

            【解决方案7】:

            您正在谈论延迟统计信息写入和会话管理。我猜你真正的问题是避免 per-http-requests 在数据库上写入查询。

            一些可能对此类问题有用的提示:

            1. 小心会话中的并行访问。我们通常认为会话只能由一个进程访问,但这是错误的,例如您正在执行多文件上传,其中一些 js 向服务器打开了多个 ajax 请求,每个进程都使用同一个会话。当您使用浏览器在同一个网站上打开 10 个标签时也是如此。
            2. 为每个请求添加更新查询是一件繁重的事情。选择查询速度很快,通常在 SQL 端使用某种缓存。更新查询很慢,可能正在重建索引,并且通常意味着在 SQL 服务器上进行一些缓存清理。如果您在数据库上使用不同的用户进行只读或读写访问,它们也可能意味着不同的 SQL 会话。
            3. 会话大小不应太大,因为必须为每个请求加载会话,并且每次在会话中写入内容时, lock 机制(因为 1)被设置并且数据被推送到物理会话存储(默认为文件)。因此会话写入会减慢您的进程。
            4. MongoDbReddit 这样的 NoSQl 后端可能是存储每个请求统计信息的好地方,它们有正确的工具来确保原子更新、锁定和可能比关系数据库执行得更快(但您也可以检查关系数据库中的内存表性能)。因此,您可以使用这些工具来跟踪活动并通过将这些后端用作实时统计的主要目标来避免 SQL 更新。您可以异步从这些后端为您的数据库收集一些静态数据。现在会话是临时对象,这些 NoSQl 后端也可以是很好的会话存储(如果您编写自己的会话存储处理程序)。

            编辑: 并行使用的原子更新问题示例:执行请求递增的查询 counter = counter +1 与读取计数器相同,递增它并执行更新查询counter = mynewvalue。当多个进程使用相同的数据时,第二个是错误的。

            【讨论】:

              【解决方案8】:

              有点偏离轨道,但您可以自己进行垃圾收集。

              • 使用 PHP 将会话保存在一个目录中,最好是 tmpfs,并禁用垃圾收集。

              • 编写一个定期 PHP 脚本来查找所有超过 20 分钟的会话文件,打开它们,将它们写入数据库并删除它们。

              【讨论】:

              • 在我看来,这是正确的答案。在您的情况下,会话不会被脚本(=用户操作)破坏,而是当它足够老可以清理时。当 any PHP 脚本运行时,这种垃圾收集通常会在给定的机会下完成。将您的会话放在一个单独的目录中,以防止它们被“外来”清理并禁用默认垃圾收集。然后创建您自己的收集器,在清理会话之前存储内容。如果你想让它独立于用户运行的 PHP 脚本,那么你需要一个 cronjob。
              猜你喜欢
              • 1970-01-01
              • 2015-03-12
              • 1970-01-01
              • 1970-01-01
              • 2019-07-15
              • 1970-01-01
              • 2023-03-20
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多