• Memcached 分布式集群


    首先解释一下我的标题,用到了 分布式 和 集群两个单词,
    为什么是集群?
    解决[相同业务]问题的服务器多个以上就称为集群.这里memcached就是做相同任务的(提供缓存服务)
    为什么是分布式?
    虽然针对的是同样的任务(缓存),但是每一台memcached存储的数据不一样,这就叫分布式.

    有很多架构是 分布式的但不叫集群(比如 把订单处理,和商品库存 分配到不同服务器上独立部署,这叫分布式),
    有很多是 集群架构但是不一定是分布式的(比如 应用服务器集群,每一台服务器上的资源一样)

    通常来说一般的集群部署表现为  一群memcached服务器 加  一台或多台 负载均衡服务器,
    应用程序 要set 一个缓存,首先是发送到 负载均衡服务器,然后由负载均衡服务器通过负载均衡算法
    分配到一台memcached服务器来存储,get 一个缓存也是同理.如下图:

    但是目前我没有看到有针对 memcached 可用的负载均衡服务器成品,
    对于memcached这种火热的缓存没道理没有解决方案啊,难道有其他的架构方式?

    我翻阅了网上很多关于memcached的分布式解决方案,都没有中间负载均衡服务器,而是把均衡算法交给
    了应用程序(客户端)来完成

    常见的两种负载算法  取模,一致性hash

    取模算法的原理:
    根据 set/get 的hash(key)值 对集群中memcached的个数取模,就可以均匀的分配到每一台memcached服务器
    例如 有3台memcacehed,如果 hash(key)=200923780;  200923780 mod 3 = 1
    现在需要往集群里面添加一台memcached , 200923780 mod 4 = 0;
    看出来了吗,还是原来的key  但是因为集群的memcached数量不一样了,导致最后链接的memcached server变了,
    3台memcached扩容到4台,大约有75%的缓存不能正确命中,当100台集群中加一台,不能命中的概率是 99% (n(n+1)),
    这个结果在大型系统中是不允许的.
    当然不考虑集群的伸缩性,这种算法效率其实是最高的,但是作为一个高素质的架构师
    怎么可能设计一个不能伸缩性的架构呢?

    一致性hash算法的原理是:

    按照集群中 server的ip 计算到 hash(ip),[这个地方的hash就是crc32],得到的值 放到下面的x轴上,

    如下图,有三个memcached服务器通过hash分别放到了具体位置上,现在应用程序 通过 set/get 的key也进行crc32(key) 落到了下面的位置.

    如图,key1落到了mem3和mem2之间,那么规定key1朝着箭头的方向找到的第一个memcached就作为目标,根据这个

    规定,key2的目标就是mem2,key3由于向箭头方向已经找不到了,那么就取反方向第一个mem1作为目标.

    现在再往集群中加一台memcached服务器mem-4:

    落到mem-1和mem-3上的缓存没有收到一点点影响,mem-2也只收到了一定的影响, mem-1和mem-4这一截的缓存落到了mem-4上,mem-4和mem-2这一截仍然落在mem-2上.

    随着机器越多,新增和减少集群机器影响变得更小.

    难道这样就完美了? 

    上图其实画得很理想化,因为hash的随机行很大,所以memcached 通过hash(ip)后在x轴上的分布可能是这样的:

    大量的key落在了mem1上,这看起来一点都不均衡O**O

    那怎么让他均衡呢,

    翻阅了网上很多文章,基本上是使用虚拟环,原理是:

    为每一个 物理 memcached 分配100-150个虚拟节点,key落在虚拟节点上,通过虚拟节点找到实际的物理节点.如图:

    虚拟节点越多,分布越均匀,但是越多也会增加找节点的时间,需要找到一个平衡点,推荐 100-150,

     php的memcached扩展中已经实现了一致性hash存储的算法,代码实例:

    <?php
    
    $mem = new Memcached();
    $mem->setOption(Memcached::OPT_HASH, Memcached::HASH_CRC);
    $mem->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);
    $servers = array(
      array('127.0.0.1', 11211, 33),
      array('127.0.0.1', 11212, 67)
    );
    $mem->addServers($servers);
    
    $mem->set('key1','value1');
    echo '<br/>';
    print_r($mem->get('key1'));
    echo '<br/>';
    $mem->set('key2','value2');
    echo '<br/>';
    print_r($mem->get('key2'));
    echo '<br/>';

    这种算法是 php-memcahed扩展提供的,如果追求灵活和可控,可以用纯php实现同样的负载算法,但是执行效率可能会下降.

    如果追求效率,也可以用c语言写一个扩展.

    我在接下来的博客中会进一步的扩展相关知识

  • 相关阅读:
    P2832 行路难
    P2634 [国家集训队]聪聪可可
    模拟退火算法
    洛谷 P2986 [USACO10MAR]Great Cow Gat…(树形dp+容斥原理)
    bzoj1040: [ZJOI2008]骑士(基环树dp)
    洛谷P2014 选课(树形dp)
    洛谷P3047 [USACO12FEB]Nearby Cows(树形dp)
    bzoj1026: [SCOI2009]windy数(数位dp)
    hdu3555Bomb(数位dp)
    hdu3652B-number(数位dp)
  • 原文地址:https://www.cnblogs.com/codeAB/p/7040575.html
Copyright © 2020-2023  润新知