当前,Memcached、Redis这类分布式kv缓存已经非常普遍。从本篇开始,本系列将分析分布式缓存相关的原理、使用策略和最佳实践。

我们知道Memcached的分布式其实是一种“伪分布式”,也就是它的服务器结点之间其实是相互无关联的,之间没有网络拓扑关系,由客户端来决定一个key是存放到哪台机器。

具体来讲,假设我有多台memcached服务器,编号分别为m0,m1,m2,…。对于一个key,由客户端来决定存放到哪台机器,那最简单的hash公式就是 key % N,其中N是机器的总数。

但这有个问题,一旦机器数变少,或者增加机器,N发生变化,那之前存放的数据就全部无效了。因为你按照新的N值取模计算出的机器编号,和当时按旧的N值取模算出的机器编号肯定是不等的,也就意味着绝大部分缓存会失效。

这个问题的解决办法就是用1种特别的Hash函数,尽可能使得,增加机器/减少机器时,缓存失效的数目降到最低,这就是Hash环,或者叫一致性Hash。

有兴趣朋友可以关注公众号“架构之道与术”, 获取最新文章。
或扫描如下二维码:

Hash环

上面说的Hash函数,只经过了1次hash,即把key hash到对应的机器编号。
而Hash环有2次Hash:
(1)把所有机器编号hash到这个环上
(2)把key也hash到这个环上。然后在这个环上进行匹配,看这个key和哪台机器匹配。

具体来讲,如下:

假定有这样一个Hash函数,其值空间为(0到2的32次方-1) ,也就是说,其hash值是个32位无整型数字 ,这些数字组成一个环。

然后,先对机器进行hash(比如根据机器的ip),算出每台机器在这个环上的位置; 再对key进行hash,算出该key在环上的位置,然后从这个位置往前走,遇到的第一台机器就是该key对应的机器,就把该(key, value) 存储到该机器上。

如下图所示:

首先计算出每台Cache服务器在环上的位置(图中的大圆圈);然后每来一个(key, value),计算出在环上的位置(图中的小圆圈),然后顺时针走,遇到的第1个机器,就是其要存储的机器。

这里的关键点是:当你增加/减少机器时,其他机器在环上的位置并不会发生改变。这样只有增加的那台机器、或者减少的那台机器附近的数据会失效,其他机器上的数据都还是有效的。

数据倾斜问题

当你机器不多的时候,很可能出现几台机器在环上面贴的很近,不是在环上均匀分布。这将会导致大部分数据,都会集中在某1台机器上。

为了解决这个问题,可以引入“虚拟机器”的概念,也就是说:1台机器,我在环上面计算出多个位置。怎么弄呢? 假设用机器的ip来hash,我可以在ip后面加上几个编号, ip_1, ip_2, ip_3, .. 把1台物理机器生个多个虚拟机器的编号。

数据首先映射到“虚拟机器上”,再从“虚拟机器”映射到物理机器上。因为虚拟机器可以很多,在环上面均匀分布,从而保证数据均匀分布到物理机器上面。

ZK的引入

上面我们提到了服务器的机器增加、减少,问题是客户端怎么知道呢?

一种笨办法就是手动的,当服务器机器增加、减少时候,重新配置客户端,重启客户端。

另外一种,就是引入ZK,服务器的节点列表注册到ZK上面,客户端监听ZK。发现结点数发生变化,自动更新自己的配置。

当然,不用ZK,用一个其他的中心结点,只要能实现这种更改的通知,也是可以的。

分布式缓存--系列1 -- Hash环/一致性Hash原理的更多相关文章

  1. 分布式缓存 - hash环/一致性hash

    一 引言 当前memcached,redis这类分布式kv缓存已经非常普遍.我们知道memcached的分布式其实是一种"伪分布式",也就是它的服务器节点之间其实是无关联的,之间没 ...

  2. Hash环/一致性Hash原理

    当前,Memcached.Redis这类分布式kv缓存已经非常普遍.从本篇开始,本系列将分析分布式缓存相关的原理.使用策略和最佳实践. 我们知道Memcached的分布式其实是一种“伪分布式”,也就是 ...

  3. 分布式缓存技术memcached学习系列(四)—— 一致性hash算法原理

    分布式一致性hash算法简介 当你看到"分布式一致性hash算法"这个词时,第一时间可能会问,什么是分布式,什么是一致性,hash又是什么.在分析分布式一致性hash算法原理之前, ...

  4. 分布式理论系列(二)一致性算法:2PC 到 3PC 到 Paxos 到 Raft 到 Zab

    分布式理论系列(二)一致性算法:2PC 到 3PC 到 Paxos 到 Raft 到 Zab 本文介绍一致性算法: 2PC 到 3PC 到 Paxos 到 Raft 到 Zab 两类一致性算法(操作原 ...

  5. hash·余数hash和一致性hash

    网站的伸缩性架构中,分布式的设计是现在的基本应用. 在memcached的分布式架构中,key-value缓存的命中通常采用分布式的算法 一.余数Hash     简单的路由算法可以使用余数Hash: ...

  6. 【分布式缓存系列】Redis实现分布式锁的正确姿势

    一.前言 在我们日常工作中,除了Spring和Mybatis外,用到最多无外乎分布式缓存框架——Redis.但是很多工作很多年的朋友对Redis还处于一个最基础的使用和认识.所以我就像把自己对分布式缓 ...

  7. CYQ.Data V5 分布式缓存Redis应用开发及实现算法原理介绍

    前言: 自从CYQ.Data框架出了数据库读写分离.分布式缓存MemCache.自动缓存等大功能之后,就进入了频繁的细节打磨优化阶段. 从以下的更新列表就可以看出来了,3个月更新了100条次功能: 3 ...

  8. 【分布式缓存系列】集群环境下Redis分布式锁的正确姿势

    一.前言 在上一篇文章中,已经介绍了基于Redis实现分布式锁的正确姿势,但是上篇文章存在一定的缺陷——它加锁只作用在一个Redis节点上,如果通过sentinel保证高可用,如果master节点由于 ...

  9. 一致性Hash(Consistent Hashing)原理剖析

    引入 在业务开发中,我们常把数据持久化到数据库中.如果需要读取这些数据,除了直接从数据库中读取外,为了减轻数据库的访问压力以及提高访问速度,我们更多地引入缓存来对数据进行存取.读取数据的过程一般为: ...

随机推荐

  1. Swift - 多线程GCD详解

    //  GCD详解 //  目录: //  1. 创建GCD队列(最常用) //  2. 自定义创建队列 //  3. 使用多线程实现延迟加载 //  4. 使用多线程实现重复(循环) //  5. ...

  2. OneThink后台模型怎么玩?

    OneThink 后台模型有个模型类型: 模型下——>设计——>表单显示分组(怎么玩?) 这个将会显示在:内——>发布文章内容的时候: 单选按钮: 内容模块显示: 枚举类型可以这样玩 ...

  3. 从零打造在线网盘系统之Hibernate框架起步

    欢迎浏览Java工程师SSH教程从零打造在线网盘系统系列教程,本系列教程将会使用SSH(Struts2+Spring+Hibernate)打造一个在线网盘系统,本系列教程是从零开始,所以会详细以及着重 ...

  4. ubuntu win7双系统设置开机启动顺序

    ctrl+alt+t打开命令终端 sudo chmod +w /boot/grub/grub.cfg (赋予该文件写权限) sudo gedit /boot/grub/grub.cfg 将set de ...

  5. php中的魔术方法(Magic methods)和魔术常亮

    PHP中把以两个下划线__开头的方法称为魔术方法,这些方法在PHP中充当了举足轻重的作用. 魔术方法包括: __construct(),类的构造函数 __destruct(),类的析构函数 __cal ...

  6. HRBUST - 1153 意外 HRBUST - 1153 (数论)

    意外 Time Limit: 1000 MS Memory Limit: 65536 K Total Submit: 326(87 users) Total Accepted: 97(63 users ...

  7. Python大数据:jieba 中文分词,词频统计

    # -*- coding: UTF-8 -*- import sys import numpy as np import pandas as pd import jieba import jieba. ...

  8. Python菜鸟之路:Django Admin后台管理功能使用

    前言 用过Django框架的童鞋肯定都知道,在创建完Django项目后,每个app下,都会有一个urls.py文件,里边会有如下几行: from django.contrib import admin ...

  9. Android复习

    第一章 1.Android系统架构:(四层) Linux内核层:为安卓设备的各种硬件提供底层的驱动. 系统运行库层:为Android系统提供主要的特性支持. 应用框架层:提供了构建应用程序可能用到的各 ...

  10. Integer.valueof 和 Integer.parseInt

    System.out.println(Integer.valueOf("127")==Integer.valueOf("127")); System.out.p ...