我有一个SilverStripe的实例,它在AWS负载均衡器后面的两台服务器上运行。为了共享会话信息,我正在运行Elasticache Redis服务器。我正在设置我的php会话存储信息如下:
ini_set('session.save_handler', 'redis');
ini_set('session.save_path', 'tcp://127.0.0.1:6379');
在我登录到CMS的管理部分后,我可以在服务器之间跳转,它会记住我,但是当在CMS的各个部分之间切换时,主部分不会呈现(AJAX调用)。据我所知,另一台服务器没有意识到(你从第二台服务器请求的是哪一台)你已经加载了CMS管理员,在响应标头中说要加载一个新版本的JS依赖项,然后去掉管理员,它就不加载了。
阅读文档SilverStripe使用Zend_Cache获取一些额外信息。我想如果我加载管理界面,然后删除缓存目录,它会复制问题。事实并非如此。
然后,我尝试使用此模块来更改Zend_Cache正在使用的存储引擎。我补充道:
SS_Cache::add_backend(
'primary_redis',
'Redis',
array(
'servers' => array(
'host' => 'localhost',
'port' => 6379,
'persistent' => true,
'weight' => 1,
'timeout' => 5,
'retry_interval' => 15,
'status' => true,
'failure_callback' => null
)
)
);
SS_Cache::pick_backend('primary_redis', 'any', 10);
对于我的mysite/\uconfig.php,这将在redis中存储一些类似密钥CMSMain_SiteTreeHints9b258b19199db9f9ed8264009b6c351b
的cms信息,但这仍然不能解决在负载平衡环境中在服务器之间更改的问题。
SilverStripe还能在哪里存储缓存数据?我是否正确实施了该模块?
默认的管理界面(假设您使用的是3.x)使用一个名为jquery.ondemand
的javascript库-它跟踪已经包含的文件(类似于"require.js
"的一种相当古老的前身-只不过没有AMD,并且支持CSS)。
为此,考虑到网络本质上是无状态的,并且您用于保存状态的方法在服务器之间共享(数据库和会话数据),这与CMS本身有任何关系的可能性很小。
在HA集群中的各个实例之间不是共享的是物理文件。这里的原因很可能(但不一定)是提供给ondemand
的URI末尾的mtime
印记——最初是为了避免主题更改(由开发人员制作或以其他方式自动化)方面的浏览器缓存问题。
毫无疑问,您已经检查过的标头包括(始终,无论HAProxy、nginx、ELB或其他什么选择的端点)X-Include-CSS
和X-Include-JS
,其中的一个示例如下:
X-Include-JS:/framework/thirdparty/jquery/jquery.js?m=1481487203,/framework/javascript/jquery-ondemand/jquery.ondemand.js?m=1481487186,/framework/admin/javascript/lib.js?m=1481487181
[…]
这是针对每个请求的,ondemand
可以检查并查看已经包含的内容以及需要添加的内容。
(顺便说一句,这些报头的大小是导致nginx
报头缓冲区问题的原因,导致"默认"设置中的502
。)
那么,该怎么办呢
如果部署静态代码,静态文件应该在平衡实例之间保持相同的mtime,但这是需要检查的。另一方面,生成的文件(如Requirements::combine_files
)需要在所有实例之间(重新)生成时同步,就像您站点的所有/assets
一样,在这种情况下,mtime应该保持不变。Zend_cache
在这里不太可能有任何影响,尽管APC
可能是一个因素。当然,在任何情况下,首先要检查的是我的前提是否成立——例如,通过diff工具从两端运行头响应。
为了帮助那些可能遇到这种情况并需要一个连接到CMS的解决方案的人,我做了以下工作:
class SyncRequirements_Backend extends Requirements_Backend implements Flushable {
protected static $flush = false;
public static function flush() {
static::$flush = true;
}
public function process_combined_files() {
// You can write your own or copy from framework/view/Requirements.php
// Do the required syncing like rsync at the appropriate spot like on successfulWrite
}
}
将Requirements::set_backend(new SyncRequirements_Backend());
添加到_config.php中(我的是一个单独的扩展,但mysite也可以)。
此解决方案的问题是,如果核心Requirements_Backend更新,您将运行旧版本的代码,但它不太可能破坏任何内容,您刚刚实现了使用相同代码的自己的Requirements后端。你可以直接调用父级,而不是自己完成所有操作,但是我找不到只在文件写入时运行同步的方法,它会在每次请求组合文件时运行。