• php利用zookeeper作dispatcher服务器


    =====

    https://blog.eood.cn/php_share_memory

    最常见的apc

    可以缓存php的opcode提高应用的性能,可以在同个php-fpm进程池间共享数据

    常见功能:

    apc_store apc_fetch
    apc_add apc_delete
    apc_inc apc_dec
    apc_cas
    apc_clear_cache
    apc_sma_info
    2,shmod unix 系统共享内存使用接口
    常见功能
    shmop_open
    shmop_close
    shmop_read
    shmop_write
    shmop_delete
    ipcs -m 查看本季共享内存的状态和统计
    ipcm -m shmid 或ipcrm -M shmkey清除共享内存中数据
    3,systemV shm
    常用的功能:
    ftok
    shm_attach
    shm_detach
    shm_put_var
    shm_get
    shm_remove_var
    4,使用共享内存需要考虑操作的原子性,锁,并行和互斥
    seg 信号量相关函数
    sem_get
    sem_remove
    sem_acquire
    sem_release(保证原子性)
    其他常见的锁机制:文件锁机制flock
    5,php提供的IPC机制
    -enable-shmop 共享内存,只能按字节操作
    -enable-sysvsem 信号量
    -enable-syssshm 共享内存,和shmop的差别是提供的操作函数不同,支持key,value操作
    -enable-sysvmsg 消息队列
    ============
    http://www.cnblogs.com/siqi/p/3997444.html
    共享内存有两套扩展可以实现:
    shmop 编译时需要开启  --enable-shmop 参数
    $shm_key = ftok(__FILE__, 't');
    
    /**
     开辟一块共享内存
     
    int $key , string $flags , int $mode , int $size 
    $flags: a:访问只读内存段
            c:创建一个新内存段,或者如果该内存段已存在,尝试打开它进行读写
            w:可读写的内存段
            n:创建一个新内存段,如果该内存段已存在,则会失败
    $mode: 八进制格式  0655
    $size: 开辟的数据大小 字节
    
     */
    
    $shm_id = shmop_open($shm_key, "c", 0644, 1024);
    
    /**
     * 写入数据 数据必须是字符串格式 , 最后一个指偏移量
     * 注意:偏移量必须在指定的范围之内,否则写入不了
     * 
     */
    $size = shmop_write($shm_id, 'songjiankang', 0);
    echo "write into {$size}";
    
    #读取的范围也必须在申请的内存范围之内,否则失败
    $data = shmop_read($shm_id, 0, 100);
    var_dump($data);
    
    #删除 只是做一个删除标志位,同时不在允许新的进程进程读取,当在没有任何进程读取时系统会自动删除
    shmop_delete($shm_id);
    
    #关闭该内存段
    shmop_close($shm_id);

    2,用semaphore扩展中的sem类函数,类似key-value格式,注意此方式和第一种方式不能通用

    // Get the file token key
    $key = ftok(__DIR__, 'a');
    
    // 创建一个共享内存
    $shm_id = shm_attach($key, 1024, 777); // resource type
    if ($shm_id === false) {
        die('Unable to create the shared memory segment');
    }
    
    #设置一个值
    shm_put_var($shm_id, 111, 'value');
    
    #删除一个key
    //shm_remove_var($shm_id, 111);
    
    #获取一个值
    $value = shm_get_var($shm_id,  111);
    var_dump($value);
    
    #检测一个key是否存在
    // var_dump(shm_has_var($shm_id,  111));
    
    #从系统中移除
    shm_remove($shm_id);
    
    #关闭和共享内存的连接
    shm_detach($shm_id);

    3,使用一个共享内存和信号量实现的消息队列

    /**
    * 使用共享内存和信号量实现
    * 
    * 支持多进程, 支持各种数据类型的存储
    * 注: 完成入队或出队操作,尽快使用unset(), 以释放临界区
    *
    */
    class ShmQueue
    {
    
        private $maxQSize = 0; // 队列最大长度
        private $front = 0; // 队头指针
        private $rear = 0; // 队尾指针
        private $blockSize = 256; // 块的大小(byte)
        private $memSize = 25600; // 最大共享内存(byte)
        private $shmId = 0;
    
        private $filePtr = './shmq.ptr';
    
        private $semId = 0;
    
        public function __construct ()
        {
            $shmkey = ftok(__FILE__, 't');
            
            $this->shmId = shmop_open($shmkey, "c", 0644, $this->memSize);
            $this->maxQSize = $this->memSize / $this->blockSize;
            
            // 申請一个信号量
            $this->semId = sem_get($shmkey, 1);
            sem_acquire($this->semId); // 申请进入临界区
            
            $this->init();
        }
    
        private function init ()
        {
            if (file_exists($this->filePtr)) {
                $contents = file_get_contents($this->filePtr);
                $data = explode('|', $contents);
                if (isset($data[0]) && isset($data[1])) {
                    $this->front = (int) $data[0];
                    $this->rear = (int) $data[1];
                }
            }
        }
    
        public function getLength ()
        {
            return (($this->rear - $this->front + $this->memSize) % ($this->memSize)) /
                     $this->blockSize;
        }
    
        public function enQueue ($value)
        {
            if ($this->ptrInc($this->rear) == $this->front) { // 队满
                return false;
            }
            
            $data = $this->encode($value);
            shmop_write($this->shmId, $data, $this->rear);
            $this->rear = $this->ptrInc($this->rear);
            return true;
        }
    
        public function deQueue ()
        {
            if ($this->front == $this->rear) { // 队空
                return false;
            }
            $value = shmop_read($this->shmId, $this->front, $this->blockSize - 1);
            $this->front = $this->ptrInc($this->front);
            return $this->decode($value);
        }
    
        private function ptrInc ($ptr)
        {
            return ($ptr + $this->blockSize) % ($this->memSize);
        }
    
        private function encode ($value)
        {
            $data = serialize($value) . "__eof";
            echo '';
            
            echo strlen($data);
            echo '';
            
            echo $this->blockSize - 1;
            echo '';
            
            if (strlen($data) > $this->blockSize - 1) {
                throw new Exception(strlen($data) . " is overload block size!");
            }
            return $data;
        }
    
        private function decode ($value)
        {
            $data = explode("__eof", $value);
            return unserialize($data[0]);
        }
    
        public function __destruct ()
        {
            $data = $this->front . '|' . $this->rear;
            file_put_contents($this->filePtr, $data);
            
            sem_release($this->semId); // 出临界区, 释放信号量
        }
    }
    
    /*
     * // 进队操作 $shmq = new ShmQueue(); $data = 'test data'; $shmq->enQueue($data);
     * unset($shmq); // 出队操作 $shmq = new ShmQueue(); $data = $shmq->deQueue();
     * unset($shmq);
     */

    ====

    我的业务逻辑:

    利用zookeeper作拓扑发现和分发的功能,

    业务的其他服务器(server1,server2,server3...)在启动的时候,向zookeeper服务器注册自身的ip地址;

    客户端首先需要获取服务器的ip地址,需要访问dispatcher服务器,

    我们现在的dispatcher服务器和zookeeper服务器是放在同一台机器上(这时候,我们不需要利用zookeeper的leader选举策略),

    当用户通过http协议访问dispatcher:

    dispatcher是一个运行生产者消费者模型的php多进程程序,

    生产者进程:利用php zookeeper的扩展,将多台服务器的ip从zookeeper中取出,放入共享内存中,

    消费者进程:就是通过http访问,利用nginx代理,通过fast-cgi产生的任务线程,这些任务线程->

    就是消费者进程,利用php中的加锁服务在同享内存中取得数据,

    -------

    写操作优先,但是需要 消息队列 来缓存来自http的请求;

    -------

     
     
  • 相关阅读:
    已知前序中序后序中的两种,如何求另一种
    sql(上)例题
    sql语句顺序/包含执行顺序和书写顺序
    VScode中文乱码问题
    好用的后台管理模板Bootstrap3
    手把手教你用Typora自动上传到picgo图床【教程与排坑】
    解决GitHub网页githubusercontent地址无法访问问题
    Java学习+面试指南(转)
    Linux C/C++ 方向学习经验【转】
    Scrapy学习笔记(一)
  • 原文地址:https://www.cnblogs.com/li-daphne/p/5718225.html
Copyright © 2020-2023  润新知