2

我们尝试在高负载环境中部署 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致命错误:未知:在第0行的未知中检测到卡住的自旋锁(0x7fcbae9fe068)

这似乎是一种超时,pthread 不会发生这种情况,因为它们不使用超时。

发生的事情可能是这样的: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 64 位。

调试起来真的很困难,我们编写了监控脚本,这些脚本每分钟从 apc、系统等处收集尽可能多的数据,但我们看不到任何异常情况——即使在崩溃前 1 分钟也是如此。

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

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

我不确定将 APC 用于本地用户缓存是否是高负载环境中的最佳选择。我们已经在这里使用过 memcached,但是 APC 要快得多。但是如何让它稳定呢?

最好的问候,安德烈亚斯

4

2 回答 2

4

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

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

那是林纳斯写的...

自旋锁很慢;该断言不是基于我在 facebook 上在线阅读的一些文章,而是基于此事的实际情况。

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

它们被内核有效地使用,因为这是它们被设计用于使用的地方,锁定微小的微小部分,而不是坐在那里等待您将您的 amazon soap 响应复制到 apc 并每秒退出 10 亿次。

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

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

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

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

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

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

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

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

我希望你能深入了解它:)

于 2013-11-12T22:19:12.110 回答
1

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

于 2013-11-11T07:32:52.723 回答