使用集群,比如zk来控制注册中心,当一个服务有多个请求地址的时候,会返回多个地址。

那么就需要负载均衡来控制我们要请求哪台机器来得到请求。

方案一:随机

传入key值和key所包含的ip地址值,该地址值存入TreeSet中(有序存储)

获得TreeSet的长度,然后随机得到其索引,挑出随机的一个。

 public String route(String serviceKey, TreeSet<String> addressSet) {
// arr
String[] addressArr = addressSet.toArray(new String[addressSet.size()]); // random
String finalAddress = addressArr[random.nextInt(addressSet.size())];
return finalAddress;
}

方案二:轮询

TreeSet中的地址值存入一个数组中,并设置一个map集合来记录该函数调用了几次,每次调用,就将索引加1,然后返回该索引的地址值。这样就会按照TreeSet中的顺序依次选取请求地址。

private ConcurrentHashMap<String, Integer> routeCountEachJob = new ConcurrentHashMap<String, Integer>();
private long CACHE_VALID_TIME = 0;
private int count(String serviceKey) {
// cache clear
if (System.currentTimeMillis() > CACHE_VALID_TIME) {
routeCountEachJob.clear();
CACHE_VALID_TIME = System.currentTimeMillis() + 24*60*60*1000;//一天的时间
} // count++
Integer count = routeCountEachJob.get(serviceKey);
count = (count==null || count>1000000)?(new Random().nextInt(100)):++count; // 初始化时主动Random一次,缓解首次压力
routeCountEachJob.put(serviceKey, count);
System.out.println("count:"+count);
return count;
} @Override
public String route(String serviceKey, TreeSet<String> addressSet) {
// arr
String[] addressArr = addressSet.toArray(new String[addressSet.size()]); // round
int i = count(serviceKey) % addressArr.length;
System.out.println(i);
String finalAddress = addressArr[i];
return finalAddress;
}

方案三: LRU(最近最少使用调度算法)

每次使用了每个节点的时候,就将该节点放置在最后面,这样就保证每次使用的节点都是最近最久没有使用过的节点,当节点数大于最大空间的时候,就直接将前面的节点删掉。

实现:使用LinkedHashMap来实现。它内部有一个双向链表在维护

public String doRoute(String serviceKey, TreeSet<String> addressSet) {

        // cache clear
if (System.currentTimeMillis() > CACHE_VALID_TIME) {
jobLRUMap.clear();
CACHE_VALID_TIME = System.currentTimeMillis() + 1000*60*60*24;//一天
} // init lru
LinkedHashMap<String, String> lruItem = jobLRUMap.get(serviceKey);
if (lruItem == null) {
/**
* LinkedHashMap
* a、accessOrder:ture=访问顺序排序(get/put时排序)/ACCESS-LAST;false=插入顺序排期/FIFO;
* b、removeEldestEntry:新增元素时将会调用,返回true时会删除最老元素;可封装LinkedHashMap并重写该方法,比如定义最大容量,超出是返回true即可实现固定长度的LRU算法;
*/
lruItem = new LinkedHashMap<String, String>(16, 0.75f, true){
@Override
protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
if(super.size() > 3){
return true;
}else{
return false;
}
}
};
jobLRUMap.putIfAbsent(serviceKey, lruItem);
} // put
for (String address: addressSet) {
if (!lruItem.containsKey(address)) {
lruItem.put(address, address);
}
} // load
String eldestKey = lruItem.entrySet().iterator().next().getKey();
String eldestValue = lruItem.get(eldestKey);//LRU算法关键体现在这里,实现了固定长度的LRU算法
return eldestValue;
}

方案四:LFU(访问最频繁的使用概率也最高),因此,将使用最频繁的放在最后面使用,保证了使用不频繁的也能使用上

hashmap的存放是无序的。

public String doRoute(String serviceKey, TreeSet<String> addressSet) {

        // cache clear
if (System.currentTimeMillis() > CACHE_VALID_TIME) {
jobLfuMap.clear();
CACHE_VALID_TIME = System.currentTimeMillis() + 1000*60*60*24;
} // lfu item init
HashMap<String, Integer> lfuItemMap = jobLfuMap.get(serviceKey); // Key排序可以用TreeMap+构造入参Compare;Value排序暂时只能通过ArrayList;
if (lfuItemMap == null) {
lfuItemMap = new HashMap<String, Integer>();
jobLfuMap.putIfAbsent(serviceKey, lfuItemMap); // 避免重复覆盖
}
for (String address: addressSet) {
if (!lfuItemMap.containsKey(address) || lfuItemMap.get(address) >1000000 ) {
lfuItemMap.put(address, 0);
}
}
// System.out.println(lfuItemMap); // load least userd count address
List<Map.Entry<String, Integer>> lfuItemList = new ArrayList<Map.Entry<String, Integer>>(lfuItemMap.entrySet());
Collections.sort(lfuItemList, new Comparator<Map.Entry<String, Integer>>() {
@Override
public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) {
return o1.getValue().compareTo(o2.getValue());
}
});
System.out.println(lfuItemList); Map.Entry<String, Integer> addressItem = lfuItemList.get(0);
String minAddress = addressItem.getKey();
addressItem.setValue(addressItem.getValue() + 1); return minAddress;
// return null;
}

方案五:一致性哈希

consistent hashing 是一种 hash 算法,简单的说,在移除 / 添加一个 cache 时,它能够尽可能小的改变已存在 key 映射关系,尽可能的满足单调性的要求。

  1. 每个节点设置5个虚拟节点

  2. 计算serviceKey的hash值

  3. 使用treeMap的tailMap方法返回其键大于或等于fromKey的部分视图

  4. 取视图的第一个作为服务调用的address

private int VIRTUAL_NODE_NUM = 5;

    /**
* get hash code on 2^32 ring (md5散列的方式计算hash值)
* @param key
* @return
*/
private long hash(String key) { // md5 byte
MessageDigest md5;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("MD5 not supported", e);
}
md5.reset();
byte[] keyBytes = null;
try {
keyBytes = key.getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Unknown string :" + key, e);
} md5.update(keyBytes);
byte[] digest = md5.digest(); // hash code, Truncate to 32-bits
long hashCode = ((long) (digest[3] & 0xFF) << 24)
| ((long) (digest[2] & 0xFF) << 16)
| ((long) (digest[1] & 0xFF) << 8)
| (digest[0] & 0xFF); long truncateHashCode = hashCode & 0xffffffffL;
return truncateHashCode;
} public String doRoute(String serviceKey, TreeSet<String> addressSet) { // ------A1------A2-------A3------
// -----------J1------------------
TreeMap<Long, String> addressRing = new TreeMap<Long, String>();
for (String address: addressSet) {
for (int i = 0; i < VIRTUAL_NODE_NUM; i++) {
long addressHash = hash("SHARD-" + address + "-NODE-" + i);
addressRing.put(addressHash, address);
}
}
//TreeMap的存放是根据addressHash值排序 long jobHash = hash(serviceKey);
SortedMap<Long, String> lastRing = addressRing.tailMap(jobHash);
//将addressHash值大于jobHash值的adress都取出来
// System.out.println(lastRing);
if (!lastRing.isEmpty()) {
//如果这个地址不为空,就返回这个的第一个
return lastRing.get(lastRing.firstKey());
}
// System.out.println(lastRing.firstKey());
//返回没有减少的地址的第一个
return addressRing.firstEntry().getValue();
}

rpc之负载均衡的更多相关文章

  1. RPC原来就是Socket——RPC框架到dubbo的服务动态注册,服务路由,负载均衡演化

    序:RPC就是使用socket告诉服务端我要调你的哪一个类的哪一个方法然后获得处理的结果.服务注册和路由就是借助第三方存储介质存储服务信息让服务消费者调用.然我们自己动手从0开始写一个rpc功能以及实 ...

  2. rpc框架之HA/负载均衡构架设计

    thrift.avro.grpc之类的rpc框架默认都没有提供负载均衡的实现,生产环境中如果server只有一台,显然不靠谱,于是有了下面的设计,这其实是前一阵跟北京一个朋友在qq群里交流的结果,分享 ...

  3. 【架构】RPC 使用 Haproxy、keepalive作为负载均衡

    参考资料: Haproxy+keepalived 高可用负载:  http://www.tuicool.com/articles/qY7Rz23 keepalived原理(主从配置+haproxy)及 ...

  4. 猜测的rpc负载均衡原理,基于dubbo的架构

    集群层(Cluster):封装多个提供者的路由及负载均衡,并桥接注册中心,以Invoker为中心,扩展接口为Cluster.Directory.Router和LoadBalance.将多个服务提供方组 ...

  5. 一致性哈希算法(适用于分库分表、RPC负载均衡)转

    在分布式应用中,应该来说使用到hash最多的地方就是rpc负载均衡和分库分表,通常对于正式意义上的分布式应用来说,扩容和收缩是一个半自动化的过程,在此期间,应用基本上是可用的,所以不能发生大规模动荡的 ...

  6. 前端学HTTP之重定向和负载均衡

    前面的话 HTTP并不是独自运行在网上的.很多协议都会在HTTP报文的传输过程中对其数据进行管理.HTTP只关心旅程的端点(发送者和接收者),但在包含有镜像服务器.Web代理和缓存的网络世界中,HTT ...

  7. 阿里巴巴的分布式应用框架-dubbo负载均衡策略--- 一致哈希算法

    dubbo是阿里巴巴公司开发的一个开源分布式应用框架,基于服务的发布者和订阅者,服务者启动服务向注册中心发布自己的服务:消费者(订阅者)启动服务器向注册中心订阅所需要的服务.注册中心将订阅的服务注册列 ...

  8. 网络负载均衡环境下wsHttpBinding+Message Security+Windows Authentication的常见异常

    提高Windows Communication Foundation (WCF) 应用程序负载能力的方法之一就是通过把它们部署到负载均衡的服务器场中. 其中可以使用标准的负载均衡技术, Windows ...

  9. 15套java互联网架构师、高并发、集群、负载均衡、高可用、数据库设计、缓存、性能优化、大型分布式 项目实战视频教程

    * { font-family: "Microsoft YaHei" !important } h1 { color: #FF0 } 15套java架构师.集群.高可用.高可扩 展 ...

随机推荐

  1. 基于视频压缩的实时监控系统-sprint1基于epoll架构的采集端程序设计

    part1:产品功能 part2:epoll机制   select与epoll区别 1.select与epoll没有太大的区别.除了select有文件描述符限制(1024个),select每次调用都需 ...

  2. 如何用Keil MDK5创建新项目

    1.安装相应软件 2.创建与Build项目 创建项目 下载与调试— ST-Link

  3. (转)海思平台HI35XX系列内存设置

    海思平台的内存分为两部分,一部分给系统使用,另外的一部分给多媒体使用.可以通过cat /proc/meminfo查看系统内存和cat /proc/media-mem 查看多媒体内存使用情况. /pro ...

  4. pandas | 详解DataFrame中的apply与applymap方法

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是pandas数据处理专题的第5篇文章,我们来聊聊pandas的一些高级运算. 在上一篇文章当中,我们介绍了panads的一些计算方法, ...

  5. C#LeetCode刷题之#34-在排序数组中查找元素的第一个和最后一个位置(Find First and Last Position of Element in Sorted Array)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/4970 访问. 给定一个按照升序排列的整数数组 nums,和一个目 ...

  6. C#LeetCode刷题之#20-有效的括号(Valid Parentheses)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/4018 访问. 给定一个只包括 '(',')','{','}',' ...

  7. [C#.NET 拾遗补漏]07:迭代器和列举器

    大家好,这是 [C#.NET 拾遗补漏] 系列的第 07 篇文章. 在 C# 中,大多数方法都是通过 return 语句立即把程序的控制权交回给调用者,同时也会把方法内的本地资源释放掉.而包含 yie ...

  8. 靶机练习 - ATT&CK红队实战靶场 - 1. 环境搭建和漏洞利用

    最近某个公众号介绍了网上的一套环境,这个环境是多个Windows靶机组成的,涉及到内网渗透,正好Windows和内网渗透一直没怎么接触过,所以拿来学习下. 下载地址:http://vulnstack. ...

  9. SpringBoot整合Spring Security

    好好学习,天天向上 本文已收录至我的Github仓库DayDayUP:github.com/RobodLee/DayDayUP,欢迎Star,更多文章请前往:目录导航 前言 Spring Securi ...

  10. Spring - RestTemplate执行原理分析

    什么是RestTemplate Synchronous client to perform HTTP requests, exposing a simple, template method API ...