菜单

四 分析easyswoole源码(运维服务&Cache组件原理)

2019年2月26日 - 金沙编程资讯

前文提到的在系统设置Cache组件
Cache::getInstance()的时候,会去调用processManager去创制Cache的进度,然后以管道通讯的不二法门开始展览安装缓存和获取缓存。

前文连接,讲了es是何等运行swoole服务的。

正文实例讲述了memcache一致性hash的php落成格局。分享给大家供我们参考。具体如下:

前边笔者写了一篇在 Laravel 4 框架中利用Ali云 OCS
缓存的稿子,介绍了哪些通过扩展Laravel 4 来协理供给 SASL 认证的Ali云 OCS 缓存服务。有网上朋友问笔者,ACE
的缓存怎么在 Laravel 4
中应用。小编本来觉得应该能够完全用平等的形式,后来自身尝尝的时候才察觉,ACE
的缓存差别相当的大。所以再写一篇,介绍一下哪些在 Laravel 框架中动用Ali云
ACE 的缓存服务。

Cache是以单例格局完毕的。构造器会进行如下操作

其中有多少个工具类TableManager。这一个类为了处理进度间数据共享。是对swoole_table的一层封装
swoole_table一个基于共享内部存款和储蓄器和锁达成的超高品质,并发数据结构。用于消除多进程/二十四线程数据共享和一块加锁难点。

最近在看有的分布式方面包车型大巴篇章,所以就用php达成一致性hash来练练手,以前一般用的是最原始的hash取模做
分布式,当生产进度中添加或删除一台memcache都会造成数据的整个失效,一致性hash正是为了化解这么些题材,把失效数据降到最低,相关资料能够google一下!

什么样扩张 Laravel 的缓存驱动

//根据配置创建指定数目的Cache服务进程,然后启动。
$num = intval(Config::getInstance()->getConf("EASY_CACHE.PROCESS_NUM"));//默认配置数目是1,在Config.php里'EASY_CACHE.PROCESS_NUM'=>1
if($num <= 0){
   return;
}
$this->cliTemp = new SplArray();//这个数组以后会给单元测试时候单独使用,正常模式这个数组是不使用的
//若是在主服务创建,而非单元测试调用
if(ServerManager::getInstance()->getServer()){
    //创建了一个swoole_table ,表名为__Cache,里面存储data(后面就讲到其实这里存储的是操作Cache的指令)作用是用来做GC(防止Cache被撑爆)
    TableManager::getInstance()->add(self::EXCHANGE_TABLE_NAME,[
        'data'=>[
            'type'=>Table::TYPE_STRING,
            'size'=>10*1024
        ],
        'microTime'=>[
            'type'=>Table::TYPE_STRING,
            'size'=>15
        ]
    ],2048);
    $this->processNum = $num;
    for ($i=0;$i < $num;$i++){
        ProcessManager::getInstance()->addProcess($this->generateProcessName($i),CacheProcess::class);
    }
}

TableManager重要做了下边几件事
add方法
一旦$list数组中有其一表名($name是三个表名或许叫做集合名),就发轫化swoole_table,然后配置的字段类型数组举办创办

php实现成效有肯定的不够,假设要高效用,依然写扩大相比好

在 Laravel 4 中动用 Cache::get($key), Cache::put($key, $value, $minutes)
那样的代码时,实际上是访问 实例化的 Illuminate\Cache\Repository,
所以我们由此 Cache::extend 方法扩大自定义缓存驱动时,同样应该回到三个Illuminate\Cache\Repository 对象。

ProcessManager::getInstance()->addProcess($this->generateProcessName($i),CacheProcess::class)那句话才是Cache的主干逻辑。

if(!isset($this->list[$name])){
    $table = new Table($size);
    foreach ($columns as $column => $item){
        $table->column($column,$item['type'],$item['size']);
    }
    $table->create();
    $this->list[$name] = $table;
}

经测试,几个memcache,各个memcache生成九1九个虚拟节点,set加get1000次,与单个memcache直接set加get慢5倍,所以效用一般,有待优化!

Laravel 4 内置的 Memcached 缓存驱动,达成的流水生产线是如此的:

ProcessManager::getInstance()那句话首要做了上边包车型的士操作
ProcessManager
的__construct构造函数成立了贰个swoole_table,表名是process_hash_map

get方法
直接回到swoole_table的实例。

在翻阅本文在此以前,最好领悟二分查找法。

1.成立一个正式 Memcached 类的新对象
2.用上一步创制的 Memcached 对象创制一个兑现了
Illuminate\Cache\StoreInterface 接口的
Illuminate\Cache\MemecachedStore 对象。
3.用上一步创建的 MemcachedStore 对象创立一个Illuminate\Cache\Repository 对象。

TableManager::getInstance()->add(
    'process_hash_map',[
        'pid'=>[
            'type'=>Table::TYPE_INT,
            'size'=>10
        ]
    ],256
);

行使的地点有很多
前文提到的在系统安装Cache组件 Cache::getInstance()的时候

完结进程:

之所以大家在扩大自定义的 Cache
驱动时,依据自身的动静,选取方面包车型地铁某四个步骤自定义,最终依旧要返回Illuminate\Cache\Repository
对象。比如上一篇文章中,作者正是在第三步,成立标准
Memcached 对象之后,通过 setSaslAuthData() 方法设定 OCS
要求的用户名密码。之后第叁步、第贰步并不须要自定义。

addProcess($this->generateProcessName($i),CacheProcess::class);
$this->generateProcessName($i)那个代码非常的粗略正是基于$i来设置进程名称
addProcess 是在processList存款和储蓄CacheProcess::class的实例,具体代码如下

构造方法做了如下事情

memcache的铺排 ip+端口+虚拟节点种类号
做hash,使用的是crc32,形成3个闭环。
对要操作的key进行crc32
二分法在虚拟节点环中查找近来的二个虚构节点
从虚拟节点中领取真实的memcache ip和端口,做单例连接

ACE 的缓存服务

$key = md5($processName);
if(!isset($this->processList[$key])){
    try{

        $process = new $processClass($processName,$args,$async);
        $this->processList[$key] = $process;
        return true;
    }catch (\Throwable $throwable){
        Trigger::throwable($throwable);
        return false;
    }
}else{
    trigger_error("you can not add the same name process : {$processName}.{$processClass}");
    return false;
}
$num = intval(Config::getInstance()->getConf("EASY_CACHE.PROCESS_NUM"));//Config默认配置是1,如果配置为小于等于0则不开启Cache
if($num <= 0){
   return;
}
$this->cliTemp = new SplArray();
//若是在主服务创建,而非单元测试调用
if(ServerManager::getInstance()->getServer()){
    //创建table用于数据传递
    TableManager::getInstance()->add(self::EXCHANGE_TABLE_NAME,[
        'data'=>[
            'type'=>Table::TYPE_STRING,
            'size'=>10*1024
        ],
        'microTime'=>[
            'type'=>Table::TYPE_STRING,
            'size'=>15
        ]
    ],2048);
    //创建了一个__Cache的swoole_table表,字段为 data String 10240,microTime String 15的表
    $this->processNum = $num;
    for ($i=0;$i < $num;$i++){
        ProcessManager::getInstance()->addProcess($this->generateProcessName($i),CacheProcess::class);
    }
}

复制代码 代码如下:

Ali云 ACE 的缓存服务,跟暗中同意的 OCS 有所不一致:

那么CacheProcess::class的实例话做了什么操作呢
$this->cacheData = new
SplArray();//那里很重点,为啥这么说每一种Cache进度实际保存的缓存值都以在那里的,每个Cache进度都有和好的二个cacheData数组
$this->persistentTime =
Config::getInstance()->getConf(‘EASY_CACHE.PERSISTENT_TIME’);
parent::__construct($processName, $args);
CacheProcess::class继承于AbstractProcess
AbstractProcess的构造方法

ProcessManager也是3个很首要的定义。其实正是一个管制职务映射的工具。

<?php
class memcacheHashMap {
        private $_node = array();
        private $_nodeData = array();
        private $_keyNode = 0;
        private $_memcache = null;
        //每一种物理服务器生成虚拟节点个数
[注:节点数愈来愈多,cache分布的均匀性越好,同时set
get操作时,也更功耗源,10台物理服务器,接纳200较为合理]
        private $_virtualNodeNum = 200;
        private function __construct() {
                $config = array(//五个memcache服务器
                                                ‘127.0.0.1:11211’,
                                                ‘127.0.0.1:11212’,
                                                ‘127.0.0.1:11213’,
                                                ‘127.0.0.1:11214’,
                                                ‘127.0.0.1:11215’
                                        );
                if (!$config) throw new Exception(‘Cache config
NULL’);
                foreach ($config as $key => $value) {
                        for ($i = 0; $i < $this->_virtualNodeNum;
$i++) {
                                $this->_node[sprintf(“%u”,
crc32($value . ‘_’ . $i))] = $value . ‘_’ .
$i;//循环为各种memcache服务器创设200个虚拟节点
                        }
                }
               
ksort($this->_node);//创造出来的1000个虚拟节点依照键名从小到大排序
        }
        //实例化该类
        static public function getInstance() {
                static $memcacheObj = null;
                if (!is_object($memcacheObj)) {
                        $memcacheObj = new self();
                }
                return $memcacheObj;
        }
        //根据传来的键查找到呼应虚拟节点的地点
        private function _connectMemcache($key) {
                $this->_nodeData =
array_keys($this->_node);//全部的虚构节点的键的数组
                $this->_keyNode = sprintf(“%u”,
crc32($key));//算出键的hash值
                $nodeKey =
$this->_findServerNode();//找出相应的杜撰节点
               
//假诺超出环,从头再用二分法查找二个近来的,然后环的头尾做判定,取最接近的节点
                if ($this->_keyNode > end($this->_nodeData))
{
                        $this->_keyNode -=
end($this->_nodeData);
                        $nodeKey2 = $this->_findServerNode();
                        if (abs($nodeKey2 – $this->_keyNode) <
abs($nodeKey – $this->_keyNode))  $nodeKey = $nodeKey2;
                }
                var_dump($this->_node[$nodeKey]);
                list($config, $num) = explode(‘_’,
$this->_node[$nodeKey]);
                if (!$config) throw new Exception(‘Cache config
Error’);
                if (!isset($this->_memcache[$config])) {
                        $this->_memcache[$config] = new
Memcache;
                        list($host, $port) = explode(‘:’, $config);
                       
$this->_memcache[$config]->connect($host, $port);
                }
                return $this->_memcache[$config];
        }
        //二分法依据提交的值找出多年来的虚拟节点地点
        private function _findServerNode($m = 0, $b = 0) {
            $total = count($this->_nodeData);
            if ($total != 0 && $b == 0) $b = $total – 1;
            if ($m < $b){
                $avg = intval(($m+$b) / 2);
                if ($this->_nodeData[$avg] == $this->_keyNode)
return $this->_nodeData[$avg];
                elseif ($this->_keyNode <
$this->_nodeData[$avg] && ($avg-1 >= 0)) return
$this->_findServerNode($m, $avg-1);
                else return $this->_findServerNode($avg+1, $b);
            }
                if (abs($this->_nodeData[$b] –
$this->_keyNode) < abs($this->_nodeData[$m] –
$this->_keyNode))  return $this->_nodeData[$b];
                else return $this->_nodeData[$m];
        }
        public function set($key, $value, $expire = 0) {
                return $this->_connectMemcache($key)->set($key,
json_encode($value), 0, $expire);
        }
        public function add($key, $value, $expire = 0) {
                return $this->_connectMemcache($key)->add($key,
json_encode($value), 0, $expire);
        }
        public function get($key) {
                return
json_decode($this->_connectMemcache($key)->get($key), true);
        }
        public function delete($key) {
                return
$this->_connectMemcache($key)->delete($key);
        }
}
$runData[‘BEGIN_TIME’] = microtime(true);
//测试三千0次set加get
for($i=0;$i<10000;$i++) {
        $key = md5(mt_rand());
        $b = memcacheHashMap::getInstance()->set($key, time(), 10);
}
var_dump(number_format(microtime(true) –
$runData[‘BEGIN_TIME’],6));
$runData[金沙国际,’BEGIN_TIME’] = microtime(true); $m= new Memcache;
$m->connect(‘127.0.0.1’, 11211);
for($i=0;$i<10000;$i++) {
        $key = md5(mt_rand());
        $b = $m->set($key, time(), 0, 10);
}
var_dump(number_format(microtime(true) –
$runData[‘BEGIN_TIME’],6));
?>

1.通过 Alibaba(Alibaba)::Cache() 方法获得 Cache 对象。
2.ACE 的 Cache 对象与正式 Memcached 对象区别,帮助的法子简单。

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图