关于使用PHP对一致性哈希的实现

配置Memcached服务

参考:https://www.runoob.com/memcached/memcached-connection.html

一致性哈希原理介绍

把个服务器节点映射放在钟表的各个时刻上,把key也映射到钟表的某个时刻上,这样实现节点的均匀分布。

定义接口

<?php
namespace CacheInterface;
interface Distribution
{
	//获取服务名称所在的节点。
	public function lookup($key);
}
interface Hash
{
	//计算服务名称的节点名称
	public function _hash($str);
}

实现Hash接口的逻辑

namespace CacheAlgo;
use CacheInterface\Distribution;
use CacheInterface\Hash;
class Consistent implements Hash,Distribution
{
	//一致性哈希
	protected $_nodes 	 = [];
	protected $_position = [];
	protected $_mul      = 64;
	
	public function _hash($str)
    {
        return sprintf('%u', crc32($str));
    }
   
    public function lookup($key)
    {
        $point = $this->_hash($key);
        $node  = current($this->_position);
        foreach ($this->_position as $k => $v) {
            if ($point <= $k) {
                $node = $v;
                break;
            }
        }

        return $node;
    }
	
	//添加一个节点,虚拟化64个虚拟节点
    public function addNode($node)
    {
        for ($i = 0; $i < $this->_mul; $i++) {
            $this->_position[$this->_hash($node . '-' . $i)] = $node;
        }
        $this->_sortPos();
    }
	
	//删除节点
    public function delNode($node)
    {
        foreach ($this->_position as $key => $value) {
            if ($value == $node) {
                unset($this->_position[$key]);
            }
        }
    }
	
	//对节点进行排序
    protected function _sortPos()
    {
        ksort($this->_position, SORT_REGULAR);
    }
	
	//调试节点
    public function printPost()
    {
        dump($this->_position);
    }
}

接入测试用例

准备Memcache服务器

<?php
#config.php
return [
	 'memcache_server' => [
        'A' => [
            'host' => '127.0.0.1',
            'port' => 11211
        ],
        'B' => [
            'host' => '127.0.0.1',
            'port' => 11212
        ],
        'C' => [
            'host' => '127.0.0.1',
            'port' => 11213
        ],
        'D' => [
            'host' => '127.0.0.1',
            'port' => 11214
        ],
        'E' => [
            'host' => '127.0.0.1',
            'port' => 11215
        ],
    ],
    'mamcache_dis' =>  \CacheAlgo\Consistent::class,
];
#启动服务:memcached.exe -m 64 -p 11211 -vvv

准备图形程序 index.html

<!DOCTYPE HTML>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>Memcache的一致性哈希演示</title>
	<style type="text/css">
       #container {
           min-width: 310px;
            height: 400px;
            margin: 0 auto;
     	}
	</style>
</head>
<body>
<!----highcharts第三方js图库--->
<script src="/Public/js/Hicharts/code/highcharts.js"></script>
<script src="/Public/js/Hicharts/code/modules/exporting.js"></script>
<script src="/Public/js/Hicharts/code/modules/export-data.js"></script>
<script src="/Public/js/jquery-1.8.3.min.js"></script>
<div id="container"></div>
<script type="text/javascript">
Highcharts.chart('container', {
    chart: {
        type: 'spline',
        animation: Highcharts.svg, // don't animate in old IE
        marginRight: 10,
        events: {
            load: function () {
                // set up the updating of the chart each second
                var series = this.series[0];
                setInterval(function () {
                    //var sto=parseFloat($.ajax({url:'<{:U("loadAjax")}>',async:false}).responseText);
                    var x = (new Date()).getTime(), // current time
                        y = parseFloat($.ajax({url:'数据加载URL',async:false}).responseText);
                    series.addPoint([x, y], true, true);
                }, 3000);
            }
        }
    },
    time: {
        useUTC: false
    },
    title: {
        text: 'Memcache his'
    },
    xAxis: {
        type: 'datetime',
        tickPixelInterval: 150
    },
    yAxis: {
        title: {
            text: 'Value'
        },
        plotLines: [{
            value: 0,
            width: 1,
            color: '#808080'
        }]
    },
    tooltip: {
        headerFormat: '<b>{series.name}</b><br/>',
        pointFormat: '{point.x:%Y-%m-%d %H:%M:%S}<br/>{point.y:.2f}'
    },
    legend: {
        enabled: false
    },
    exporting: {
        enabled: false
    },
    series: [{
        name: 'Random data',
        data: (function () {
            // generate an array of random data
            var data = [],
                time = (new Date()).getTime(),
                i;

            for (i = -19; i <= 0; i += 1) {
                data.push({
                    x: time + i * 1000,
                    y: Math.random()
                });
            }
            return data;
        }())
    }]
});
</script>
	</body>
</html>

测试用例程序

<?php
//这里使用的是TP3程序,其他框架自己改写下,就行了
class IndexController
{
	//初始化方法:初始化数据
	public function initialData()
    {
        set_time_limit(0);
        $memcache     = new \Memcache();
        $diser_server = C('mamcache_dis');
        $host         = C('memcache_server');
        $diser        = new $diser_server();
        foreach ($host as $key => $vals) {
            $diser->addNode($key);
        }
        for ($i = 0; $i < 100; $i++) {
            $i        = sprintf('%04d', $i);
            $key      = 'key' . $i;
            $value    = 'value' . $i;
            $host_key = $diser->lookup($key);
            dump($host_key);
            $serv = $host[$host_key];
            $memcache->connect($serv['host'], $serv['port'], 2);
            $memcache->add($key, $value, 0, 0);
            //usleep(3000);
        }
        echo '初始化完毕';
    }
    //展示方法
	public function index()
    {
        $this->display();
    }
	
	//数据加载方法:数据实时加载...,即上面的index.html中数据加载URL
    public function loadAjax()
    {
        $gets          = 0;
        $hits          = 0;
        $mem           = new \Memcache();
        $configMemserv = C('memcache_server');
        foreach ($configMemserv as $k => $s) {
            $res = $mem->connect($s['host'], $s['port'], 2);
            // //dump($res);
            // //echo $k,'号服务器的统计情况是';
            // //dump($mem->getStats());
            // //echo '<br />---------';
            $res = $mem->getStats();
            //dump($res);
            // //dump($res);
            $gets += $res['cmd_get'];
            $hits += $res['get_hits'];
            // //$mem->flush();
            // //dump($res);
        }
        $rato = 1;
        if ($gets > 0) {
            $rato = $hits / $gets;
        }
        echo $rato;
    }
    
    //宕机方法:减少命中率,即模拟一台Memcache服务器宕机。
	public function descHitRato()
    {
        set_time_limit(0);
        $dis_server   = C('mamcache_dis');
        $diser        = new $dis_server();
        $server_maser = C('memcache_server');
        foreach ($server_maser as $ks => $value) {
            $diser->addNode($ks);
        }
        //减少一台服务器
        $diser->delNode('D');
        $mem = new \Memcache();
        for ($i = 1; $i <= 100; $i++) {
            $i        = sprintf('%04d', $i);
            $key      = 'key' . $i;
            $serv_key = $diser->lookup($key);
            //dump($serv_key);
            //echo $serv_key;continue;
            $serv = $server_maser[$serv_key];
            $res  = $mem->connect($serv['host'], $serv['port'], 2);
            if (!$mem->get($key)) {
                $mem->add($key, 'value' . $i, 0, 0);
            }
           // usleep(3000);
        }
    }
}

详情介绍

整理中…

发布了46 篇原创文章 · 获赞 3 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/tangqing24680/article/details/103524132