一致性取模方法缺点: 嗯,比起以上两种,可以认为没有。
三、单元测试
OK,不废话,接下来上单元测试,假设有三个节点,每个节点有三个虚拟节点的情况
package com.hyh.core.test; import com.hyh.utils.common.StringUtils; import org.junit.Test; import java.util.LinkedList; import java.util.List; import java.util.SortedMap; import java.util.TreeMap; /** * 一致性HASH TEST * * @Author heyuhua * @create 2021/1/31 19:50 */ public class ConsistentHashTest { //待添加入Hash环的服务器列表 private static String[] servers = {"192.168.5.1", "192.168.5.2", "192.168.5.3"}; //真实结点列表,考虑到服务器上线、下线的场景,即添加、删除的场景会比较频繁,这里使用LinkedList会更好 private static List<String> realNodes = new LinkedList<>(); //虚拟节点,key表示虚拟节点的hash值,value表示虚拟节点的名称 private static SortedMap<Integer, String> virtualNodes = new TreeMap<>(); //一个真实结点对应3个虚拟节点 private static final int VIRTUAL_NODES = 3; /** * 测试有虚拟节点的一致性HASH */ @Test public void testConsistentHash() { initNodes(); String[] users = {"user1", "user2", "user3", "user4", "user5", "user6", "user7", "user8", "user9"}; for (int i = 0; i < users.length; i++) System.out.println("[" + users[i] + "]的hash值为" + getHash(users[i]) + ", 被路由到结点[" + getServer(users[i]) + "]"); } /** * 先把原始的服务器添加到真实结点列表中 */ public void initNodes() { for (int i = 0; i < servers.length; i++) realNodes.add(servers[i]); for (String str : realNodes) { for (int i = 0; i < VIRTUAL_NODES; i++) { String virtualNodeName = str + "-虚拟节点" + String.valueOf(i); int hash = getHash(virtualNodeName); System.out.println("虚拟节点[" + virtualNodeName + "]被添加, hash值为" + hash); virtualNodes.put(hash, virtualNodeName); } } System.out.println(); } //使用FNV1_32_HASH算法计算服务器的Hash值,这里不使用重写hashCode的方法,最终效果没区别 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; } //得到应当路由到的结点 private static String getServer(String key) { //得到该key的hash值 int hash = getHash(key); // 得到大于该Hash值的所有Map SortedMap<Integer, String> subMap = virtualNodes.tailMap(hash); String virtualNode; if (subMap.isEmpty()) { //如果没有比该key的hash值大的,则从第一个node开始 Integer i = virtualNodes.firstKey(); //返回对应的服务器 virtualNode = virtualNodes.get(i); } else { //第一个Key就是顺时针过去离node最近的那个结点 Integer i = subMap.firstKey(); //返回对应的服务器 virtualNode = subMap.get(i); } //virtualNode虚拟节点名称要截取一下 if (StringUtils.isNotBlank(virtualNode)) { return virtualNode.substring(0, virtualNode.indexOf("-")); } return null; } }
这里模拟9个用户对象hash后被路由的情况,看下结果
总结:
分库分表在分布式微服务架构环境下建议强烈使用一致性HASH
算法来做,当然分布式环境下也会产生业务数据数据一致性、分布式事务问题,下期咱们再来探讨数据一致性、分布式事务的解决方案
到此这篇关于MySQL
分库分表详情的文章就介绍到这了,更多相关MySQL
分库分表内容请搜索
更多Mysql内容来自木庄网络博客
标签:Mysql
相关阅读 >>
更多相关阅读请进入《mysql》频道 >>

数据库系统概念 第6版
本书主要讲述了数据模型、基于对象的数据库和XML、数据存储和查询、事务管理、体系结构等方面的内容。