技术心得记录:架构设计之数据分片

简介: 技术心得记录:架构设计之数据分片

数据分片技术作为目前架构设计中处理大数据的一种常规手段,当前被广泛用于缓存、数据库、消息队列等中间件的开发与使用当中,例如在数据量较大的项目当中,系统的性能瓶颈主要来自于与数据库的交互,而通过合理的设计数据库分片规则,可将系统中的数据分布在不同的物理数据库中,平衡了单点的数据量与访问压力,达到提升应用系统数据处理速度的目的,从而提高系统的整体性能;


数据库分片的概念


数据分片概念就是按照一定的规则,将数据集划分成相对独立的数据子集,然后将数据子集分布到不同的节点上,这个节点可以是逻辑上节点,也可以是物理上的节点。数据分片需要按照一定的规则,不同的分布式场景需要设计不同的规则,但基本都遵循同样的原则:按照最主要、最频繁使用的访问方式来分片。在常规的项目开发当中,一般有以下三种方式对数据进行分片:hash方式、一致性hash、按照数据范围,每种分片方式是否适用,一方面需要结合项目的实际情况与规模,另一方面也要从几个常规的维度去评估:


1、 数据分片策略,也就是具体的分片方式


2、 数据分片节点的动态扩展,随着数据量的逐步增长,是否能够通过增加节点来动态扩展适应


3、 数据分片节点的负载均衡‘,结合分片策略能否保证数据均匀的分布在各个节点上以及各个节点的负载压力是否均衡


4、 数据分片的可用性,当其中一个节点产生异常,能否将该节点的数据转移到其他节点上


下面我们就对三种常规的分片模式做个基本的介绍


hash方式


通过对数据(一般为Key值)先进行hash计算再取模的方式是一种简单且使用频繁的分片方式,也就是Hash(Key)%N,这里的N大部分情况下就是我们的结点个数,这种方式相对简单实用,一般场景下能够满足我们的要求。但Hash取模方式主要的问题是节点扩容或缩减的时候,会产生大量的数据迁移,比如从N台设备扩容到N+1台,绝大部分的数据都要在设备间进行迁移。该种方式代码实现较为简单,既可以采用jdk自带的hash方式也可以采用其他hash算法,大家可以自行搜索具体实现。


一致性hash


一致性hash是将数据按照特征值映射到一个首尾相接的hash环上,同时也将节点映射到这个环上。对于数据,从数据在环上的位置开始,顺时针找到的第一个节点即为数据的存储节点。这种模式的优点在于节点一旦需要扩容或缩减的时候只会影响到hash环上相邻的节点,不会发生大规模的数据迁移。分片方式如下图所示


但是常规的一致性hash分片模式也有缺点,一致性hash方式在增加节点的时候,只能分摊一个已存在节点的压力,在其中一个节点挂掉的时候,该节点的压力也会被全部转移到下一个节点。理想的目标是当节点动态发生变化时,已存在的所有节点都能参与进来,达到新的均衡状态。因此在实际开发中一般会引入虚拟节点(virtual node)的概念,即不是将物理节点映射在hash环上,而是将虚拟节点映射到hash环上。虚拟节点的数目远大于物理节点,因此一个物理节点需要负责多个虚拟节点的真实存储。操作数据的时候,先通过hash环找到对应的虚拟节点,再通过虚拟节点与物理节点的映射关系找到对应的物理节点。


引入虚拟节点后的一致性hash需要维护的元数据也会增加:第一,虚拟节点在hash环上的问题,且虚拟节点的数目又比较多;第二,虚拟节点与物理节点的映射关系。但带来的好处是明显的,当一个物理节点失效时,hash环上多个虚拟节点失效,对应的压力也就会发散到多个其余的虚拟节点,事实上也就是多个其余的物理节点。在增加物理节点的时候同样如此。除此之外,可以根据物理节点的性能来调整每一个物理节点对于虚拟节点的数量,充分、合理利用资源。下面看下引入虚拟节点的一致性hash的代码实现


/


节点信息



*/


class Node {


private String host;//IP信息


private int load;//负载因子


public String getHost() {


return host;


}


public void setHost(String host) {


this.host = host;


}


public int getLoad() {


return load;


}


public void setLoad(int load) {


this.load = load;


}


public Node(String host, int load) {


super();


this.host = host;


this.load = load;


}


@Override


public String toString() {


return "Node 【host=" + host + ", 负载因子=" + load + "】";


}


}


// 真实节点列表


private static List realNodes = new ArrayList();


// 虚拟节点,key是Hash值,value是虚拟节点信息


private static SortedMap virtualMap = new TreeMap();


static {


//初始化真实节点列表


realNodes.add(new Node("192.168.1.1", 5));


realNodes.add(new Node("192.168.1.2", 10));


//代码效果参考:http://www.jhylw.com.cn/233722673.html

realNodes.add(new Node("192.168.1.3", 20));

realNodes.add(new Node("192.168.1.4", 5));


for (Node node : realNodes) { //添加虚拟节点


for (int i = 0; i < node.getLoad(); i++) {


String server = node.getHost();


String virtualNode = server + "&&VN" + i;


int hash = getHash(virtualNode);


virtualMap.put(hash, virtualNode);


}


}


}


/


FNV1_32_HASH算法


/


private static int getHash(String str) {


final int p = 16777619;


int hash = (int) 2166136261L;


for (int i = 0; i < str.length(); i++)


hash = (hash ^ str.charAt(i)) p;


hash += hash [ 13;


hash ^= hash ] 7;


hash += hash [ 3;


hash ^= hash ] 17;


hash += hash [ 5;


// 如果算出来的值为负数则取其绝对值


if (hash < 0)


hash = Math.abs(hash);


return hash;


}


/**


获取被分配的节点名



@param node


@return


/


public static Node getNode(String key) {


int hash = getHash(key);//


Integer keyNode = null;


// 得到大于该Hash值的所有Map


SortedMap subMap = virtualMap.tailMap(hash);


if (subMap.isEmpty()) {//在这里形成一个环形结构


//如果没有比该key的hash值大的,则从第一个node开始


keyNode = virtualMap.firstKey();


} else {


//获取第一个key值,也就是顺时针第一个节点


keyNode = subMap.firstKey();


}


String virtualNode = virtualMap.get(keyNode);//获取虚拟节点


String realNodeName = virtualNode.substring(0, virtualNode.indexOf("&&"));


for (Node node : realNodes) {//根据虚拟节点获取真实节点


if (node.getHost().equals(realNodeName)) {


return node;


}


}


return null;


}


按数据范围(range based)


按数据范围分片其实也就是基于数据的业务属性进行分片,如唯一编码、时间戳、使用频率等,比如在数据库层面按ID范围、按时间进行分库、分表、分片,按数据被访问频率分为热点库与历史库等方法,都是按数据范围方式的具体应用。基于数据范围的分片模式需要贴合项目实际场景,使用中需要注意以下几点:


1、 分片与扩展实现比较简单,结合ID范围、时间结合业务自行实现即可;


2、较为依赖备份机制,否则某个节点发生异常无法迅速恢复,可用性较难保证;?


3、对数据规模要有前瞻性的评估,例如按时间分片,需要考虑单位时间片内数据分布是否均匀;


4、注意各分片数据之间的性能平衡,因为在常规场景下,无论采用哪种基于数据范围的分片模式,都是距离当前时间点较近的数据被访问和操作的几率较大,所以要特别注意随着数据规模与时间的推移,历史数据规模不断膨胀导致的整体性能下降。


综上是对项目开发中我们使用的数据分片模式的一个简单总结,hash与一致性hash有着相对固定的实现方式,按数据范围则需要结合业务数据属性进行分析,我们要意识到数据分片在项目中不是一个孤立的问题,它关系着数据备份、一致性、可用性、负载均衡、数据访问与操作等等一系列问题,所以需要系统性的去学习与思考,本文内容只是一个基础性的阐述与总结,其中如有不足与不正确的地方还望指正与海涵,十分感谢。

相关文章
|
7天前
|
存储 分布式计算 数据挖掘
数据架构 ODPS 是什么?
数据架构 ODPS 是什么?
59 7
|
7天前
|
数据采集 搜索推荐 数据管理
数据架构 CDP 是什么?
数据架构 CDP 是什么?
22 2
|
8天前
|
运维 Kubernetes Cloud Native
云原生技术:容器化与微服务架构的完美结合
【10月更文挑战第37天】在数字化转型的浪潮中,云原生技术以其灵活性和高效性成为企业的新宠。本文将深入探讨云原生的核心概念,包括容器化技术和微服务架构,以及它们如何共同推动现代应用的发展。我们将通过实际代码示例,展示如何在Kubernetes集群上部署一个简单的微服务,揭示云原生技术的强大能力和未来潜力。
|
6天前
|
存储 分布式计算 关系型数据库
架构/技术框架调研
本文介绍了微服务间事务处理、调用、大数据处理、分库分表、大文本存储及数据缓存的最优解决方案。重点讨论了Seata、Dubbo、Hadoop生态系统、MyCat、ShardingSphere、对象存储服务和Redis等技术,提供了详细的原理、应用场景和优缺点分析。
|
9天前
|
监控 API 微服务
后端技术演进:从单体架构到微服务的转变
随着互联网应用的快速增长和用户需求的不断演化,传统单体架构已难以满足现代软件开发的需求。本文深入探讨了后端技术在面对复杂系统挑战时的演进路径,重点分析了从单体架构向微服务架构转变的过程、原因及优势。通过对比分析,揭示了微服务架构如何提高系统的可扩展性、灵活性和维护效率,同时指出了实施微服务时面临的挑战和最佳实践。
28 7
|
6天前
|
传感器 算法 物联网
智能停车解决方案之停车场室内导航系统(二):核心技术与系统架构构建
随着城市化进程的加速,停车难问题日益凸显。本文深入剖析智能停车系统的关键技术,包括停车场电子地图编辑绘制、物联网与传感器技术、大数据与云计算的应用、定位技术及车辆导航路径规划,为读者提供全面的技术解决方案。系统架构分为应用层、业务层、数据层和运行环境,涵盖停车场室内导航、车位占用检测、动态更新、精准导航和路径规划等方面。
37 4
|
8天前
|
Kubernetes Cloud Native 持续交付
云原生技术在现代应用架构中的实践与思考
【10月更文挑战第38天】随着云计算的不断成熟和演进,云原生(Cloud-Native)已成为推动企业数字化转型的重要力量。本文从云原生的基本概念出发,深入探讨了其在现代应用架构中的实际应用,并结合代码示例,展示了云原生技术如何优化资源管理、提升系统弹性和加速开发流程。通过分析云原生的优势与面临的挑战,本文旨在为读者提供一份云原生转型的指南和启示。
22 3
|
10天前
|
网络协议 数据挖掘 5G
适用于金融和交易应用的低延迟网络:技术、架构与应用
适用于金融和交易应用的低延迟网络:技术、架构与应用
38 5
|
7天前
|
运维 Kubernetes Cloud Native
云原生技术在现代应用架构中的实践与挑战####
本文深入探讨了云原生技术的核心概念、关键技术组件及其在实际项目中的应用案例,分析了企业在向云原生转型过程中面临的主要挑战及应对策略。不同于传统摘要的概述性质,本摘要强调通过具体实例揭示云原生技术如何促进应用的灵活性、可扩展性和高效运维,同时指出实践中需注意的技术债务、安全合规等问题,为读者提供一幅云原生技术实践的全景视图。 ####
|
12天前
|
Kubernetes Cloud Native 云计算
云原生技术深度解析:重塑企业IT架构的未来####
本文深入探讨了云原生技术的核心理念、关键技术组件及其对企业IT架构转型的深远影响。通过剖析Kubernetes、微服务、容器化等核心技术,本文揭示了云原生如何提升应用的灵活性、可扩展性和可维护性,助力企业在数字化转型中保持领先地位。 ####