APC用户缓存适用于高负载环境?

时间:2013-11-07 22:30:31

标签: php crash apc spinlock high-load

我们尝试在高负载环境中将APC用户缓存部署为每个服务器上的本地第二层缓存,用于我们的中央缓存服务(redis),用于缓存具有很少更改结果和配置的数据库查询。我们基本上看了Facebook(多年前)的所作所为:

http://www.slideshare.net/guoqing75/4069180-caching-performance-lessons-from-facebook http://www.slideshare.net/shire/php-tek-2007-apc-facebook

它在一段时间内运行良好,但在高负载下运行几个小时后,APC遇到问题,因此整个mod_php不再执行任何PHP。 即使只是一个简单的PHP脚本也不再回答,而Apache仍然提供静态资源。它没有真正崩溃,没有段错误。我们尝试了最新稳定和最新的APC测试版,我们尝试了pthreads,旋转锁,每次都出现同样的问题。我们为APC提供了更多可以消耗的内存,在崩溃前1分钟我们有2%的碎片,大约90%的内存是免费的。当它“崩溃”时,我们在错误日志中找不到任何内容,只有重启Apache才有帮助。只有旋转锁我们得到一个php错误:

  

PHP致命错误:未知:检测到陷入螺旋锁(0x7fcbae9fe068)   第0行未知

这似乎是一种超时,pthreads不会发生,因为那些不使用超时。

发生的事情可能是这样的: http://notmysock.org/blog/php/user-cache-timebomb.html

一些数字:服务器每秒大约有400个APC用户缓存命中率,每秒大约有30个插入(我认为这很多),一个请求有大约20-100个用户缓存请求。用户缓存中有大约300,000个变量,都有ttl(我们只在我们的中央redis中存储没有ttl)。

我们的APC设置是:

apc.shm_segments=1 
apc.shm_size=4096M
apc.num_files_hint=1000
apc.user_entries_hint=500000
apc.max_file_size=2M
apc.stat=0

目前我们正在使用版本3.1.13-beta与自旋锁编译,与旧的PHP 5.2.6一起使用(它是一个遗留的应用程序,我听说这个PHP版本也可能是一个问题?),Linux 64bit

调试真的很难,我们编写了监控脚本,收集尽可能多的数据,我们可以从apc,系统等每分钟收集,但我们看不到任何不寻常的事情 - 甚至在崩溃前1分钟。

我在这里看到了很多类似的问题,但到目前为止我们还找不到解决问题的解决方案。当我读到这样的东西时:

http://webadvent.org/2010/share-and-enjoy-by-gopal-vijayaraghavan

我不确定在高负载环境中使用APC进行本地用户缓存是最好的选择。我们已经在这里使用了memcached,但是APC要快得多。但是如何让它保持稳定?

最好的问候, 安德烈亚斯

2 个答案:

答案 0 :(得分:4)

第1课:https://www.kernel.org/doc/Documentation/spinlocks.txt

  

上面的单个自旋锁原语绝不是唯一的原语。他们   是最安全的,在所有情况下都能工作的,   但部分因为它们是安全的,它们也相当慢。它们比较慢   比他们需要的,因为他们必须禁用中断   (这只是x86上的一条指令,但它是一个昂贵的指令 -   而在其他架构上可能更糟糕。)

那是由Linus写的......

旋转锁很慢;这个断言不是基于我在Facebook上在线阅读的一些文章,而是基于事实的实际情况。

这也是一个偶然的事实,因为你所说的问题,自旋锁被部署在高于内核的级别;由于执行不当导致无法追踪的死锁。

它们被内核高效使用,因为它是设计用于的地方,锁定微小的小部分,而不是坐在那里等待你将亚马逊肥皂反应复制到apc和每秒退出十亿次。

APC中最合适的锁定类型(对于Web而不是内核)是肯定是 rwlocks,你必须在旧版APC中使用configure选项启用rwlocks,它是默认的APCu。

可以给出的最佳建议,我已经给出了,不要使用自旋锁,如果互斥锁导致你的堆栈死锁,那么试试rwlocks。

在我继续之前,你的主要问题是你使用的是古代的PHP版本,没有人甚至记得如何支持,一般来说你应该看看升级,我知道对OP的限制,但否则提到这是一个真正的问题是不负责任的,你不想部署在不受支持的软件上。此外,APC几乎没有维护,它注定要死。 O +和APCu是现代PHP版本的替代品。

无论如何,我离题了......

当你在内核级别使用自旋锁或其他任何东西进行编程时,同步是一个令人头痛的问题。当您从内核中删除多个层时,当您依赖于6或7位复杂软件时,您正确地进行同步以使您的代码能够正确同步,同步变得不仅是程序员的头痛,也是执行者的头痛;它很容易成为您闪亮的Web应用程序的瓶颈,即使在您的实现中没有错误。

令人高兴的是,这是2013年,雅虎并不是唯一能够在PHP中实现用户缓存的人:)

http://pecl.php.net/package/yac

对于用户态PHP来说,这是一个非常聪明的无锁缓存,它被标记为实验性的,但是一旦你完成了,可以玩它,也许再过7年我们就不会考虑同步问题:)

我希望你深究它:)

答案 1 :(得分:1)

除非你使用freebsd派生的操作系统,否则使用自旋锁并不是一个好主意,它们是地球上最糟糕的同步。你必须在freebsd中使用它们的唯一原因是因为实现者否定了对互斥锁和rwlocks的PTHREAD_PROCESS_SHARED支持,所以你别无选择,只能在这种情况下使用pg-sql启发的自旋锁。