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进行预处理。

最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 137,213评论 19赞 139
  • from http://www.infoq.com/cn/articles/etcd-interpretation...
    小树苗苗阅读 14,143评论 3赞 38
  • 由于文章太长,简书放不下,完整文档见Consul文档。 一、安装 Consul Consul 的安装很简单,安装 ...
    FlySheep_ly阅读 10,515评论 1赞 13
  • 本文来自作者 未闻 在 GitChat 分享的{基于 Docker 的微服务架构实践} 前言 基于 Docker ...
    AI乔治阅读 7,756评论 0赞 71
  • 张君在一家私企已经3年了,职位从小白到客户经理。他自从进入单位以后,一直都踏踏实实的做事。从最开始什么都不懂,只能...
    职场星阅读 813评论 0赞 0

友情链接更多精彩内容