适用于所有请求的 PHP Singleton 类

发布于 2024-12-04 16:55:42 字数 1579 浏览 1 评论 0原文

我有一个简单的问题。我使用 php 作为服务器部分并有 html 输出。我的网站显示有关其他服务器的状态。所以流程是:

  1. 浏览器用户访问 www.example.com/status
  2. 浏览器联系 www.example.com/status
  3. PHP 服务器接收请求并在 www.statusserver.com/status 上请求 stauts
  4. PHP 接收数据,将其转换为可读的形式HTML 输出并将其发送回客户端
  5. 浏览器用户可以看到状态。

现在,我在 php 中创建了一个单例类,它只需 8 秒即可访问状态服务器。所以它会更新状态 8 秒。如果用户在中间请求更新,服务器将返回本地(在 www.example.com 上)存储的状态。

这很好不是吗?但后来我做了一个简单的测试,启动了 5 个浏览器窗口,看看它是否有效。到了这里,php 服务器为每个请求创建了一个单例类。现在有 5 个客户端在 8 秒内请求状态服务器上的状态。这意味着我每 8 秒就会对状态服务器进行 5 次调用,而不是 1 次!

是否有可能只为 apache 服务器中的所有用户提供一个实例?如果有 1000 个用户连接到 www.example.com/status...,这将解决问题。

感谢任何提示

====================== ======= 编辑:

我已经在硬盘上使用缓存:

public function getFile($filename)
{
    $diff = (time()-filemtime($filename));
    //echo "diff:$diff<br/>";
    if($diff>8){
        //echo 'grösser 8<br/>';
        self::updateFile($filename);
    }
    if (is_readable($filename)) {
        try {
            $returnValue = @ImageCreateFromPNG($filename);
            if($returnValue == ''){
                sleep(1);
                return self::getFile($filename);
            }else{
                return $returnValue;    
            }
        } catch (Exception $e){
            sleep(1);
            return self::getFile($filename);
        }
    } else {
        sleep(1);
        return self::getFile($filename);
    }
}

这是单例中的调用。我调用一个文件并将其保存在硬盘上。但所有请求同时调用它并开始请求状态服务器。

我认为唯一的解决方案是一个独立的应用程序,它每 8 秒更新一次文件...所有请求都应该只读取文件,而不能更新它。 这个独立的可以是一个 perl 脚本或类似的东西......

I have a simple problem. I use php as server part and have an html output. My site shows a status about an other server. So the flow is:

  1. Browser user goes on www.example.com/status
  2. Browser contacts www.example.com/status
  3. PHP Server receives request and ask for stauts on www.statusserver.com/status
  4. PHP Receives the data, transforms it in readable HTML output and send it back to the client
  5. Browser user can see the status.

Now, I've created a singleton class in php which accesses the statusserver only 8 seconds. So it updates the status all 8 seconds. If a user requests for update inbetween, the server returns the locally (on www.example.com) stored status.

That's nice isn't it? But then I did an easy test and started 5 browser windows to see if it works. Here it comes, the php server created a singleton class for each request. So now 5 Clients requesting all 8 seconds the status on the statusserver. this means I have every 8 second 5 calls to the status server instead of one!

Isn't there a possibility to provide only one instance to all users within an apache server? That would be solve the problem in case 1000 users are connecting to www.example.com/status....

thx for any hints

=============================
EDIT:

I already use a caching on harddrive:

public function getFile($filename)
{
    $diff = (time()-filemtime($filename));
    //echo "diff:$diff<br/>";
    if($diff>8){
        //echo 'grösser 8<br/>';
        self::updateFile($filename);
    }
    if (is_readable($filename)) {
        try {
            $returnValue = @ImageCreateFromPNG($filename);
            if($returnValue == ''){
                sleep(1);
                return self::getFile($filename);
            }else{
                return $returnValue;    
            }
        } catch (Exception $e){
            sleep(1);
            return self::getFile($filename);
        }
    } else {
        sleep(1);
        return self::getFile($filename);
    }
}

this is the call in the singleton. I call for a file and save it on harddrive. but all the request call it at same time and start requesting the status server.

I think the only solution would be a standalone application which does an update every 8 seconds on the file... All request should just read the file and nomore able to update it.
This standalone could be a perl script or something similar...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

绅刃 2024-12-11 16:55:42

Php 请求由不同的进程处理,每个进程都有不同的状态,不像其他 Web 开发框架那样有任何常驻进程。您应该使用某些缓存等直接在类中处理该行为。

查询服务器状态的方法应该有这样的逻辑

public function getStatus() {
  if (!$status = $cache->load()) {
    // cache miss
    $status = // do your query here
    $cache->save($status); // store the result in cache
  }
  return $status;
}

,这样只有X的一个请求才能获取真实的状态。 X 值取决于您的缓存配置。

您可以使用一些缓存库:

或者您可以将结果存储在纯文本文件中,并在每个请求时检查文件本身的 m_time 和如果超过 xx 秒,则重写它。

更新

你的代码很奇怪,为什么所有这些sleep调用?为什么当 ImageCreateFromPNG 不抛出时 try/catch 块?

您问的是一个不同的问题,因为 php 不是应用程序服务器,不能跨进程存储状态,您的方法是正确的。我建议您使用 APC(使用共享内存,因此它至少比读取文件快 10 倍)在不同进程之间共享状态。使用这种方法,您的代码可能会变成

public function getFile($filename)
{
    $latest_update = apc_fetch('latest_update');
    if (false == $latest_update) {
      // cache expired or first request
      apc_store('latest_update', time(), 8); // 8 is the ttl in seconds
      // fetch file here and save on local storage
      self::updateFile($filename);
    }
    // here you can process the file
    return $your_processed_file;
}

使用这种方法,仅当进程 在 if 行之后被阻止,这不应该发生,因为它几乎是一个原子操作。

此外,如果您想确保,您应该使用类似 的内容信号量来处理这个问题,但这对于这种需求来说是一个过大的解决方案。

最后,恕我直言,8 秒是一个很小的间隔,我会使用更大的间隔,至少 30 秒,但这取决于您的要求。

Php requests are handled by different processes and each of them have a different state, there isn't any resident process like in other web development framework. You should handle that behavior directly in your class using for instance some caching.

The method which query the server status should have this logic

public function getStatus() {
  if (!$status = $cache->load()) {
    // cache miss
    $status = // do your query here
    $cache->save($status); // store the result in cache
  }
  return $status;
}

In this way only one request of X will fetch the real status. The X value depends on your cache configuration.

Some cache library you can use:

Or you can store the result in plain text file and on every request check for the m_time of the file itself and rewrite it if more than xx seconds are passed.

Update

Your code is pretty strange, why all those sleep calls? Why a try/catch block when ImageCreateFromPNG does not throw?

You're asking a different question, since php is not an application server and cannot store state across processes your approach is correct. I suggest you to use APC (uses shared memory so it would be at least 10x faster than reading a file) to share status across different processes. With this approach your code could become

public function getFile($filename)
{
    $latest_update = apc_fetch('latest_update');
    if (false == $latest_update) {
      // cache expired or first request
      apc_store('latest_update', time(), 8); // 8 is the ttl in seconds
      // fetch file here and save on local storage
      self::updateFile($filename);
    }
    // here you can process the file
    return $your_processed_file;
}

With this approach the code in the if part will be executed from two different processes only if a process is blocked just after the if line, which should not happen because is almost an atomic operation.

Furthermore if you want to ensure that you should use something like semaphores to handle that, but it would be an oversized solution for this kind of requirement.

Finally imho 8 seconds is a small interval, I'd use something bigger, at least 30 seconds, but this depends from your requirements.

德意的啸 2024-12-11 16:55:42

据我所知,这在 PHP 中是不可能的。但是,您当然可以序列化并缓存对象实例。
查看 http://php.net/manual/en/language.oop5.serialization .php

As far as I know it is not possible in PHP. However, you surely can serialize and cache the object instance.
Check out http://php.net/manual/en/language.oop5.serialization.php

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文