php项目部署方案,php与配置中心

PHP的问题

表面上看,无论是使用哪个配置中心实现方案甚至是mysql去保存配置差异都不会太大;但如果我们把php这一应用程序实现语言考虑进去的话,问题俨然会变得异常棘手起来。

与c#、Java、Go、Python、Node.JS等等应用不同,php的程序不支持常驻内存,php每处理完一个请求后,资源都会被释放掉;这也就意味着如果我们在请求进来时,都需要去访问配置中心获得各种配置信息。

因为配置中心是外部程序,每次访问都是跨进程通讯;假设获取一个配置需要耗时1ms,那么一百项配置就是0.1s;这是巨大的潜在性能影响。

无论使用什么配置中心实现,我们都很可能需要对php做特殊处理。

曾有php电商使用memcached保存一些配置信息,我压测的时候发现这些配置信息读取是耗时最大的操作一。

如果我们要引入swoole这样的php运行方案以“缓存”配置信息的话

又很可能需要对现有的php项目代码大幅度的检查、修改。

缓存方案

因为php的动态性,我们可以使用动态生成php文件的形式来做缓存,比方说参考Graphiq的方案,我们可以尝试使用写这样的函数:

$cache_path = '/tmp/confcache';

function cache_set($key, $val) {

global $cache_path;

echo "set key: $key";

$val = var_export($val, true);

// HHVM fails at __set_state, so just use object cast for now

$val = str_replace('stdClass::__set_state', '(object)', $val);

// Write to temp file first to ensure atomicity

$tmp = $cache_path.$key."." . uniqid('', true) . '.tmp';

file_put_contents($tmp, '<?php $val = ' . $val . ';', LOCK_EX);

rename($tmp, "$cache_pathe$key");

}

function get_key($key) {

global $cache_path;

if(!substr($key, 0, 1) === "/") {

throw new Exception('key must start with /');

}

@include "$cache_path$key";

if(isset($val)) {

return $val;

}

$client = new ConfigClient();

$val = $client->get($key);

cache_set($key, $val);

return $val;

}

get_key函数会首先尝试include跟key名相关的php缓存文件,如果文件存在,便可以直接返回配置值。

如果不存在,则调用etcd去获得配置值,然后写入缓存文件。

因为缓存的php文件会进一步被opcache编译、缓存起来,这样子后续的读性能,便跟直接读程序常量无异;完全不需要担心性能问题。

缓存实时更新

另一方面,我们也可以使用类似confd这样的工具做去监控watch配置中心中各个值。

在值发生变更时,便触发脚本去删除掉缓存文件,那么下次程序再调用get_key函数时,便会自动去配置中心获得新值,并重新缓存。

若opcache开启了file_cache等配置,脚本还可能需要显式的去调用opcache_invalidate去过期脚本缓存。

这方案的核心是利用了php内置的opcache来实现缓存,可靠性会非常很高。

其他参考

etcd

etcd官方不支持php,而其第三方库都非常不活跃:

即便我们不考虑常驻内存的问题,etcd的php客户端可能都需要仔细研究一下才可以使用。

consul

consul官方同样不支持php,但其第三方库稍微好一丢丢:

不过,consul的template功能导可能被用来解决php这特有问题。

consul template可以接收任意文本文件,然后调用consul服务器,将文本文件中placeholder替换为具体的配置值,最后输出为新的文本文件。

也就是说,我们可以将现有的php config文件内容修改为类似:

// application components

'components' => array(

'user' => array(

'key' => '{{key "web/user-key"}}',

),

'email' => array(

'Username' => '{{key "email/username"}}',

'Password' => '{{key "email/password"}}',

// ..

)

)

这样的形式,然后在程序部署前,先使用consul template进行预处理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值