关于php的共享内部存款和储蓄器的使用和钻研之外部存款和储蓄,运营服务

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

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

上文:至于php的共享内部存款和储蓄器的应用和研讨之由起
下文:
至于php的共享内部存款和储蓄器的施用和研商之深切剖析swoole
table

入门教导 [编辑本页]

Swoole就算是正式的PHP扩张,实际上与普通的恢宏不一致。普通的扩展只是提供三个库函数。而swoole增加在运转后会接管PHP的控制权,进入事件循环。当IO事件时有产生后,swoole会自动回调内定的PHP函数。

  • 新手入门教程:

Swoole供给使用者必须有所一定的Linux/Unix环境编程基础,《学习Swoole须要控制怎么着基础知识》
本文列出了基础知识清单。

其间有一个工具类TableManager。那几个类为了处理进程间数据共享。是对swoole_table的一层封装
swoole_table五个基于共享内部存款和储蓄器和锁达成的超高品质,并发数据结构。用于消除多进程/十二线程数据共享和协助举行加锁问题。

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

上文中关系了针对性php的共享内存方案的尝试,最终发现它并不适用于小编的光景,倘诺想要包容多进度或十二线程并发读写的事态下可信赖,一定要有适量的建制来保证财富的唯一性。

swoole_server

强有力的TCP/UDP
Server框架,二十多线程,伊夫ntLoop,事件驱动,异步,Worker进度组,Task异步任务,皮秒定时器,SSL/TLS隧道加密。

  • swoole_http_serverswoole_server的子类,内置了Http的支持
  • swoole_websocket_serverswoole_http_server的子类,内置了WebSocket的支持
  • swoole_redis_serverswoole_server的子类,内置了Redis服务器端协议的支撑

子类能够调用父类的保有办法和质量

TableManager首要做了下边几件事
add方法
如果$list数组中有其一表名($name是一个表名大概叫做集合名),就早先化swoole_table,然后配置的字段类型数组实行创办

//根据配置创建指定数目的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);
    }
}

加锁肯定是想到的第贰精选,对于每一遍共享内部存储器的时候,先得到二个锁,只有获得成功了今后才同意开始展览读和写,那应该是最简易的方案,可是共同锁对质量的费用也是相比较大的。APC的user
data
cache的仓库储存机制对数据须要从严科学,锁相比多,它的频率与本土的memcache格外。既然那样,不如把眼光投向产业界,看看大牛们运用什么的方案来缓解那一个题材。

关于php的共享内部存款和储蓄器的使用和钻研之外部存款和储蓄,运营服务。swoole_client

TCP/UDP/UnixSocket客户端,支持IPv4/IPv6,补助SSL/TLS隧道加密,协理SSL客户端整数,帮衬同步并发调用,也帮忙异步事件驱动编制程序。

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;
}

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

YAC

初稿链接:http://www.laruence.com/2013/03/18/2846.html

laurance为了消除如下的四个难题,设计出了那么些cache:

  • 想让PHP进度之间共享一些简易的数量
  • 企望13分高效的缓存一些页面

关于php的共享内部存款和储蓄器的使用和钻研之外部存款和储蓄,运营服务。而且也是依据如下的阅历若是:

  • 对于叁个采纳来说, 同名的Cache键, 对应的Value, 大小差不多杰出.
  • 今非昔比的键名的个数是零星的.
  • Cache的读的次数, 远远超乎写的次数.
  • Cache不是数据库, 就算Cache失效也不会带来沉重错误.

贯彻那么些cache,关键是无锁化的设计.
依据laurance的说教,他化解读锁的办法是经过不加锁的读,然后C安德拉C校验。
看了刹那间她代码的贯彻,是对key中蕴藏的固定size的值举行了CPRADOC的揣测,然后把key中附带存款和储蓄的crc消息和剧情总括出来的crc音讯实行校验。假设校验成功了,那么认为查询成功,假使校验退步了,那么认为查询失利。其实本质上那是一种选拔CPU来换锁的措施,大部分的服务器是多核的,一旦加锁,对CPU是非常大的浪费。下边那张图形象的注解了那或多或少:

www.5929.com 1

yac_lock.png

以此是个科学的trick,能够消除的题材就是在多少个经过频仍的写入的时候,或许引致的读出错不会带来错误的结果,因为一旦crc校验不通过,那么读出来的结果就是失效了。那鲜明比上一篇文章中的共享内部存款和储蓄器的读的章程要得力一些。可是据悉自个儿的观赛,使用共享内部存储器的艺术,由于一向是向后不停的写入,出现被覆盖的票房价值大约平昔不,而laurance那里之所以要校验,则是因为她会进行内部存款和储蓄器的回收和循环写入,那一点在下文中会继续表明。

如今重中之重说说这一个YAC的写入的难点,首先运营的时候key空间大小明确,可以因此配备来调动分配给存储key的高低,从而扩充key的个数。4M大抵约等于327六15个Cache值。首先第3个很要紧的点就是怎么规划哈希方法来防止写入争辩,那里她采纳的是双散列法的
MurmurHash.

对此小于4M的内部存款和储蓄器块的操作由于key区别,依据哈希出来的初阶地方也不比。不一致key之间争辨的可能率,等同于哈希算法争辩的可能率,那一个依然比较低的。对于大的内部存款和储蓄器块,那里运用了segment->pos指针来控制内部存款和储蓄器的分块。和共享内存扩充的兑现方式依旧相比接近了,反正正是二个pos指针,找获得就update,找不到就向后写。

那正是说一旦产生争执呢,laurance给出了三个例子:

比如A进度申请了40字节, B进度申请了60字节, 可是Pos只扩大了60字节.
那几个时候有如下二种情景:

  1. A写完了多少, 重临成功, 不过B进度又写完了数据重回成功,
    最后B进度的Cache种上了, 而A进程的被踢出了.
  2. B进度写完了数量, 再次来到成功, A进度又写完了数码再次来到成功,
    最后A进度的Cache种上了, B进程的被踢出.
  3. A进度写一半, B进度写二分一, 然后A进度又写二分一, B进度又写八分之四,
    都再次来到成功, 但最后, 缓存都失效.

足见, 最要紧的不当, 就是A和B的缓存都失效,
不过Yac不会把错误数据重临给用户, 当下2次来查询Cache的时候,
因为存在crc校验, 所以都miss.

探望那儿终于知道了,并没有解决多进度写的难题,多进度的写依旧唯恐会有争执,不仅仅是单key的抵触,不一致key之间也恐怕会有争辩。但是争论了不畏,会透过校验的章程确认保障client端可以看清出来自个儿冲突了,那点对应用程序确实越发首要,因为这不是cache
error,而单单是cache
miss而已,那二种情形的严重程度和拍卖体制真正完全区别。

其余还有1个独到之处是内部存款和储蓄器的轮回分配,假设二个内存块用完了,那么能够重置pos,从而从头先导分配,有了那种机制,尽管出现写导致pos平昔后移,也不会产出内部存款和储蓄器耗尽的景况了,那真的是个不错的性状。

小结来看,yac七个科学的特色:

  • 读的C卡宴C校验,保险最惨重是cache miss
  • 写的pos重置,保险内部存储器不被写满

但是本着自身的应用情状,多并发情形下的同key的多写多读,它并从未很好的缓解那么些题材,而是比较适用于低频的用户数据的缓存,比如登陆用户的头像、昵称那类音讯。拉取频次不高,miss了也能向后端请求。所以如何是好吧,只可以继续举行求索。

ps:laurance在篇章起始群嘲了须臾间APC的属性,相当于地点的memcache,结果文末贴出的品质相比,yac完全比不上apc。。有点莫名

swoole_event

伊夫ntLoop
API,让用户能够直接操作底层的风浪循环,将socket,stream,管道等Linux文件参与到事件循环中。

eventloop接口仅可用于socket类型的文本描述符,不能够用于磁盘文件读写

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

ProcessManager::getInstance()那句话首要做了上面包车型大巴操作
ProcessManager
的__construct构造函数创制了二个swoole_table,表名是process_hash_map

Swoole table

吸收来说说那两年在社区中间相比较火,方今正巧宣布了安置协程2.0版本的swoole.
github地址:https://github.com/swoole/swoole-src

swoole
table是swoole中的二个基于共享内存和锁达成的超高质量的面世数据结构,用来缓解多进度、二十二十四线程数据共享和协助举行加锁的题材。那不便是我们苦苦搜索的化解方案么?

先来看一下swoole table的科学普及的行使格局,首先它帮衬三种基本的门类:

  • swoole_table::TYPE_INT 整形字段
  • swoole_table::TYPE_FLOAT 浮点字段
  • swoole_table::TYPE_STRING 字符串字段

如果想要在相继进程之间共享高品质的地头数据,那么使用的范例如下:

// 新建swoole table,并且指定类型
$table = new swoole_table(1024);
$table->column('id', swoole_table::TYPE_INT, 4);       //1,2,4,8
$table->column('name', swoole_table::TYPE_STRING, 64);
$table->column('num', swoole_table::TYPE_FLOAT);
$table->create();

// 新建swoole的server
$serv = new swoole_server('127.0.0.1', 9501);
//将table保存在serv对象上
$serv->table = $table;
$serv->on('receive', function ($serv, $fd, $from_id, $data) {
    // 使用swoole table存储全局的数据
    $ret = $serv->table->set($key, array('from_id' => $data, 'fd' => $fd, 'data' => $data));
});

// 这里需要注意的就是一定要在server启动之前创建swoole table,从而保证它能够被全局共享
$serv->start();

一旦只是你本身的叁个历程在分歧的乞请之间共享高质量的地头数据,那么使用的范例如下:

class LocalSwooleTable {
    private static $_swooleTable;// 静态变量,单个进程内共享

    const SWOOLE_TABLE_SET_FAILED = -1001;
    const SWOOLE_TABLE_GET_FAILED = -1002;

    // swoole table初始化
    private function __construct() {
        //预估数据量 100个服务,每个长度30 需要3000个字节,这里申请64k
        self::$_swooleTable = new \swoole_table(65536);
        self::$_swooleTable->column('ip',\swoole_table::TYPE_STRING, 64);
        self::$_swooleTable->column('port',\swoole_table::TYPE_INT, 4);
        self::$_swooleTable->column('timestamp',\swoole_table::TYPE_INT, 4);
        self::$_swooleTable->column('bTcp',\swoole_table::TYPE_INT, 4);
        self::$_swooleTable->create();
    }

    // 获取单个swoole的实例
    public static function getInstance() {
        if(self::$_swooleTable) {
            return self::$_swooleTable;
        }
        else {
            new LocalSwooleTable();
            return self::$_swooleTable;
        }
    }
}
// 获取唯一的实例
$swooleTableIns = LocalSwooleTable::getInstance();
$key = "sample";
$routeInfo['timestamp'] = time();
$routeInfo['ip'] = '10.25.22.33';
$routeInfo['port'] = 1000;
$routeInfo['bTcp'] = 1;

// 设置swoole table中的内容
$flag = $swooleTableIns->set($key,$routeInfo);

// 获取swoole table中的内容
$routeInfo = $swooleTableIns->get($key);

当然,第壹种方法应该是我们最好的精选,可是因为大家利用了TSF框架(或然其余不是友好开班裸写swoole的框架),都不会把创造server这一步暴光到业务代码中,那就给大家选择全局的swoole的table带来了十分大的难度。换句话说,知道好用,不过正是业务用起来12分的不便于,不拥有业务扩张性。

故而不得已之下,我们照旧采纳了第三种方案,从性质方面来讲的话,确实是有晋升的,倒霉的地点正是存款和储蓄能源浪费了一部分,每个进度都用了依附自身的swoole
table,那自然是可望而不可及之举。还是希望能够之后通过有个别改建,把全局的swoole
table那种力量能够开放出来。

www.5929.com 2

荧屏快速照相 2017-01-24 上午5.28.17.png

大多访问1遍是0.03ms,那个性子照旧相比特出的。

swoole_www.5929.com,async

异步IO接口,提供了
异步文件系统IO,定时器,异步DNS查询,异步MySQL等API,异步Http客户端,异步Redis客户端。

  • swoole_timer 异步纳秒定时器,能够兑现间隔时间或贰遍性的定时职责
  • swoole_async_read/swoole_async_write 文件系统操作的异步接口

应用的地点有成都百货上千
前文提到的在系统安装Cache组件 Cache::getInstance()的时候

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

swoole_process

进程管理模块,能够方便的创制子进度,进度间通讯,进度管理。

构造方法做了之类事情

addProcess($this->generateProcessName($i),CacheProcess::class);
$this->generateProcessName($i)这些代码很简单正是依照$i来设置进程名称
addProcess 是在processList存储CacheProcess::class的实例,具体代码如下

swoole_buffer

强劲的内部存储器区管理工科具,像C一样实行指针总结,又无需关切内部存款和储蓄器的申请和刑释,而且并非操心内部存款和储蓄器越界,底层全体坚实了。

$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);
    }
}
$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;
}

swoole_table

依照共享内部存款和储蓄器和自旋锁实现的超高质量内部存款和储蓄器表。彻底化解线程,进程间数据共享,加锁同步等题材。

swoole_table的属性能够高达单线程每秒读写100W次

现实扶持文书档案地址:

ProcessManager也是一个很关键的概念。其实就是多少个管理任务映射的工具。

那正是说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::getInstance()->addProcess($this->generateProcessName($i),CacheProcess::class)

$this->async = $async;
$this->args = $args;
$this->processName = $processName;
$this->swooleProcess = new \swoole_process([$this,'__start'],false,2);
ServerManager::getInstance()->getServer()->addProcess($this->swooleProcess);//然后swoole服务会addProcess一个Cache的任务进程。

实际上那里是经过ProcessManager,让swoole服务添加了2个经过。swoole的addProcess方法,文书档案链接

__start方法主如果给swoole_table,表名为process_hash_map插入当前CacheProcess的历程名为key,进度IDpid为value。并且注册进程退出的轩然大波。

www.5929.com 3

if(PHP_OS != 'Darwin'){
    $process->name($this->getProcessName());
}
TableManager::getInstance()->get('process_hash_map')->set(
    md5($this->processName),['pid'=>$this->swooleProcess->pid]
);
ProcessManager::getInstance()->setProcess($this->getProcessName(),$this);
if (extension_loaded('pcntl')) {
    pcntl_async_signals(true);
}
Process::signal(SIGTERM,function ()use($process){
    $this->onShutDown();
    TableManager::getInstance()->get('process_hash_map')->del(md5($this->processName));
    swoole_event_del($process->pipe);
    $this->swooleProcess->exit(0);
});
if($this->async){
    swoole_event_add($this->swooleProcess->pipe, function(){
        $msg = $this->swooleProcess->read(64 * 1024);
        $this->onReceive($msg);
    });
}
$this->run($this->swooleProcess);

提早略带讲解一下Cache的set方法加深概念

$this->run($this->swooleProcess)那几个函数是CacheProcess假若配置了persistentTime,就会张开多少个定时器定时去取$file

Config::getInstance()->getConf(‘TEMP_DI冠道’).”/{$processName}.data”;的数据备份,暗许是0约等于不会去做定时数据落地的操作

总的来看此间才是Cache组件在率先次实例化的时候做的有关事务,总结便是创办了点名数量的Cache进程绑定到swoole服务器上。在大局的process_hash_map表中能找到相应的Cache过程ID。然后Cache进度是足以以管道情势来拓展通信。

 

set缓存方法

public function set($key,$data)
{
    if(!ServerManager::getInstance()->isStart()){
        $this->cliTemp->set($key,$data);
    }
    if(ServerManager::getInstance()->getServer()){
        $num = $this->keyToProcessNum($key);
        $msg = new Msg();
        $msg->setCommand('set');
        $msg->setArg('key',$key);
        $msg->setData($data);
        ProcessManager::getInstance()->getProcessByName($this->generateProcessName($num))->getProcess()->write(\swoole_serialize::pack($msg));//直接把需要缓存的数据,封装成msg然后write给hash映射到的Cache进程
    }
}

当进度取获得的时候会回调onReceive方法

public function onReceive(string $str,...$agrs)
{
    // TODO: Implement onReceive() method.

    $msg = \swoole_serialize::unpack($str);
    $table = TableManager::getInstance()->get(Cache::EXCHANGE_TABLE_NAME);
    if(count($table) > 1900){
        //接近阈值的时候进行gc检测
        //遍历Table 依赖pcre 如果发现无法遍历table,检查机器是否安装pcre-devel
        //超过0.1s 基本上99.99%为无用数据。
        $time = microtime(true);
        foreach ($table as $key => $item){
            if(round($time - $item['microTime']) > 0.1){
                $table->del($key);
            }
        }
    }
    if($msg instanceof Msg){
        switch ($msg->getCommand()){
            case 'set':{
                $this->cacheData->set($msg->getArg('key'),$msg->getData());
                break;
            }
            case 'get':{
                $ret = $this->cacheData->get($msg->getArg('key'));
                $msg->setData($ret);
                $table->set($msg->getToken(),[
                    'data'=>\swoole_serialize::pack($msg),
                    'microTime'=>microtime(true)
                ]);
                break;
            }
            case 'del':{
                $this->cacheData->delete($msg->getArg('key'));
                break;
            }
            case 'flush':{
                $this->cacheData->flush();
                break;
            }
            case 'enQueue':{
                $que = $this->cacheData->get($msg->getArg('key'));
                if(!$que instanceof \SplQueue){
                    $que = new \SplQueue();
                    $this->cacheData->set($msg->getArg('key'),$que);
                }
                $que->enqueue($msg->getData());
                break;
            }
            case 'deQueue':{

                $que = $this->cacheData->get($msg->getArg('key'));
                if(!$que instanceof \SplQueue){
                    $que = new \SplQueue();
                    $this->cacheData->set($msg->getArg('key'),$que);
                }
                $ret = null;
                if(!$que->isEmpty()){
                    $ret = $que->dequeue();
                }
                $msg->setData($ret);
                //deQueue 有cli 服务未启动的请求,但无token
                if(!empty($msg->getToken())){
                    $table->set($msg->getToken(),[
                        'data'=>\swoole_serialize::pack($msg),
                        'microTime'=>microtime(true)
                    ]);
                }
                break;
            }
            case 'queueSize':{
                $que = $this->cacheData->get($msg->getArg('key'));
                if(!$que instanceof \SplQueue){
                    $que = new \SplQueue();
                }
                $msg->setData($que->count());
                $table->set($msg->getToken(),[
                    'data'=>\swoole_serialize::pack($msg),
                    'microTime'=>microtime(true)
                ]);
                break;
            }
        }
    }
}

那边一开端会开始展览缓存GC确定保障内部存款和储蓄器不会撑爆

set方法会直接给$this->cacheData,设置缓存值。

 

get方法比较独特,它会去给Cache进度发送get的通令,然后Cache读取到命令会将值写到_Cache,Swoole_table表中。然后再去读取(这几个会有贰个while循环,类似自旋)出缓存内容。那样的裨益,能够有限支撑能够读取到登时的多少缓存,不会因为高并发读取到最新的缓存值内容。而且仍能更有效的做gc,幸免Cache内部存款和储蓄器撑爆。

public function get($key,$timeOut = 0.01)
{
    if(!ServerManager::getInstance()->isStart()){
        return $this->cliTemp->get($key);
    }
    $num = $this->keyToProcessNum($key);
    $token = Random::randStr(9);//这个是一个凭证,是确保获取到自己此刻想获取的cache数据,和事务类似为了保证可重复读
    $process = ProcessManager::getInstance()->getProcessByName($this->generateProcessName($num));
    $msg = new  Msg();
    $msg->setArg('timeOut',$timeOut);
    $msg->setArg('key',$key);
    $msg->setCommand('get');
    $msg->setToken($token);
    $process->getProcess()->write(\swoole_serialize::pack($msg));
    return $this->read($token,$timeOut);
}

$process->getProcess()->write(\swoole_serialize::pack($msg))发这么些包给Cache进度,Cache进度会进展下边这么些操作

$ret = $this->cacheData->get($msg->getArg('key'));//获取到当前的缓存值
$msg->setData($ret);
//将当前的内容设置到_Cache表中,token是请求的时候发过来的凭证原样拼装。这有什么好处呢,就是确保在高并发下,在A时刻获取的缓存,不会拿到后面B时刻更新的值。
$table->set($msg->getToken(),[
    'data'=>\swoole_serialize::pack($msg),
    'microTime'=>microtime(true)
]);

$this->read($token,$timeOut);

//这里的操作是直接从_Cache表中获取缓存数据,如果缓存存在并且进程调度没有超时,然后在表中将取过数据的内容删除掉返回
private function read($token,$timeOut)
{
    $table = TableManager::getInstance()->get(self::EXCHANGE_TABLE_NAME);
    $start = microtime(true);
    $data = null;
    while(true){
        usleep(1);
        if($table->exist($token)){
            $data = $table->get($token)['data'];
            $data = \swoole_serialize::unpack($data);
            if(!$data instanceof Msg){
                $data = null;
            }
            break;
        }
        if(round($start - microtime(true),3) > $timeOut){
            break;
        }
    }
    $table->del($token);
    if($data){
        return $data->getData();
    }else{
        return null;
    }
}

 

//讲解一下Cache的set方法加深概念
if(!ServerManager::getInstance()->isStart()){//兼容测试模式。也就是不开启服务的情景下直接是clitemp中取缓存数据
    $this->cliTemp->set($key,$data);
}
if(ServerManager::getInstance()->getServer()){
    $num = $this->keyToProcessNum($key);//这里是通过key然后hash到应该投放的Cache进程中去。
    $msg = new Msg();
    $msg->setCommand('set');
    $msg->setArg('key',$key);
    $msg->setData($data);
    //下面一句话还是挺复杂的,根据key名hash到ProcessManager对应的映射,然后获取到swoole_process的实例,以swoole的write函数向管道内写入数据。
    ProcessManager::getInstance()->getProcessByName($this->generateProcessName($num))->getProcess()->write(\swoole_serialize::pack($msg));
    //在写完数据后,在CacheProcess的onReceive方法中可以看到对应setCommand的操作细节。其实数据都被写到了一个Arr数组中。下篇接着讲一下Cache的实现细节。这节还是主要讲TableManager和它的相关作用.
}

Leave a Comment.