Java负载均衡算法实现与原理分析(轮询、随机、哈希、加权、最小连接)

文章目录

  • 一、负载均衡算法概述
  • 二、轮询(RoundRobin)算法
    • 1、概述
    • 2、Java实现轮询算法
    • 3、优缺点
  • 三、随机(Random)算法
    • 1、概述
    • 2、Java实现随机算法
  • 四、源地址哈希(Hash)算法
    • 1、概述
    • 2、Java实现地址哈希算法
    • 3、一致性哈希
      • (1)原理
      • (2)特性
      • (3)优化
      • (4)Java实现一致性哈希算法
  • 五、加权轮询(WRR)算法
    • 1、概述
    • 2、Java实现加权轮询算法
  • 六、加权随机(WR)算法
    • 1、概述
    • 2、Java实现加权随机算法
  • 七、最小连接数(LC)算法
    • 1、概述
    • 2、Java实现最小连接数算法
  • 八、应用案例
    • 1、nginx upstream
    • 2、springcloud ribbon IRule
    • 3、dubbo负载均衡

一、负载均衡算法概述

负载均衡,英文名称为Load Balance,其含义就是指将负载(工作任务)进行平衡、分摊到多个操作单元上进行运行,例如FTP服务器、Web服务器、企业核心应用服务器和其它主要任务服务器等,从而协同完成工作任务。既然涉及到多个机器,就涉及到任务如何分发,这就是负载均衡算法问题。

二、轮询(RoundRobin)算法

1、概述

轮询即排好队,一个接一个。

2、Java实现轮询算法

手动写一个双向链表形式实现服务器列表的请求轮询算法。

public class RR {//当前服务节点Server current;//初始化轮询类,多个服务器ip用逗号隔开public RR(String serverName){System.out.println("init server list : "+serverName);String[] names = serverName.split(",");for (int i = 0; i < names.length; i++) {Server server = new Server(names[i]);if (current == null){//如果当前服务器为空,说明是第一台机器,current就指向新创建的serverthis.current = server;//同时,server的前后均指向自己。current.prev = current;current.next = current;}else {//否则说明已经有机器了,按新加处理。addServer(names[i]);}}}//添加机器void addServer(String serverName){System.out.println("add server : "+serverName);Server server = new Server(serverName);Server next = this.current.next;//在当前节点后插入新节点this.current.next = server;server.prev = this.current;//修改下一节点的prev指针server.next = next;next.prev=server;}//将当前服务器移除,同时修改前后节点的指针,让其直接关联//移除的current会被回收期回收掉void remove(){System.out.println("remove current = "+current.name);this.current.prev.next = this.current.next;this.current.next.prev = this.current.prev;this.current = current.next;}//请求。由当前节点处理即可//注意:处理完成后,current指针后移void request(){System.out.println(this.current.name);this.current = current.next;}public static void main(String[] args) throws InterruptedException {//初始化两台机器RR rr = new RR("192.168.0.1,192.168.0.2");//启动一个额外线程,模拟不停的请求new Thread(new Runnable() {@Overridepublic void run() {while (true) {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}rr.request();}}}).start();//3s后,3号机器加入清单Thread.currentThread().sleep(3000);rr.addServer("192.168.0.3");//3s后,当前服务节点被移除Thread.currentThread().sleep(3000);rr.remove();}class Server{Server prev; // 前驱Server next; // 后继String name; // 名称public Server(String name){this.name = name;}}}

初始化后,只有1,2,两者轮询
3加入后,1,2,3,三者轮询
移除2后,只剩1和3轮询

3、优缺点

实现简单,机器列表可以自由加减,且时间复杂度为o(1)。
无法针对节点做偏向性定制,节点处理能力的强弱无法区分对待。

三、随机(Random)算法

1、概述

从可服务的列表中随机取一个提供响应。

2、Java实现随机算法

随机存取的场景下,适合使用数组更高效的实现下标随机读取。
定义一个数组,在数组长度内取随机数,作为其下标即可。非常简单。

public class Rand {// 所有服务ipArrayList<String> ips ;//初始化随机类,多个服务器ip用逗号隔开public Rand(String nodeNames){System.out.println("init list : "+nodeNames);String[] nodes = nodeNames.split(",");//初始化服务器列表,长度取机器数ips = new ArrayList<>(nodes.length);for (String node : nodes) {ips.add(node);}}//请求void request(){//下标,随机数,注意因子int i = new Random().nextInt(ips.size());System.out.println(ips.get(i));}//添加节点,注意,添加节点会造成内部数组扩容//可以根据实际情况初始化时预留一定空间void addnode(String nodeName){System.out.println("add node : "+nodeName);ips.add(nodeName);}//移除void remove(String nodeName){System.out.println("remove node : "+nodeName);ips.remove(nodeName);}public static void main(String[] args) throws InterruptedException {Rand rd = new Rand("192.168.0.1,192.168.0.2");//启动一个额外线程,模拟不停的请求new Thread(new Runnable() {@Overridepublic void run() {while (true) {try {Thread.sleep(500);} catch (InterruptedException e) {e.printStackTrace();}rd.request();}}}).start();//3s后,3号机器加入清单Thread.currentThread().sleep(3000);rd.addnode("192.168.0.3");//3s后,当前服务节点被移除Thread.currentThread().sleep(3000);rd.remove("192.168.0.2");}
}

初始化为1,2,两者不按顺序轮询,而是随机出现。
3加入服务节点列表。
移除2后,只剩1,3,依然是两者随机,无序。

四、源地址哈希(Hash)算法

1、概述

对当前访问的ip地址做一个hash值,相同的key被路由到同一台机器去。场景常见于分布式集群环境下,用户登录时的请求路由和会话保持。

2、Java实现地址哈希算法

使用HashMap可以实现请求值到对应节点的服务,其查找时的时间复杂度为o(1)。固定一种算法,将请求映射到key上即可。

举例,将请求的来源ip末尾,按机器数取余作为key:

public class Hash {// 所有服务ipArrayList<String> ips ;//初始化hash类,多个服务器ip用逗号隔开public Hash(String nodeNames){System.out.println("init list : "+nodeNames);String[] nodes = nodeNames.split(",");//初始化服务器列表,长度取机器数ips = new ArrayList<>(nodes.length);for (String node : nodes) {ips.add(node);}}//添加节点,注意,添加节点会造成内部Hash重排,思考为什么呢???//这是个问题!在一致性hash中会进入详细探讨void addnode(String nodeName){System.out.println("add node : "+nodeName);ips.add(nodeName);}//移除void remove(String nodeName){System.out.println("remove node : "+nodeName);ips.remove(nodeName);}//映射到key的算法,这里取余数做下标private int hash(String ip){int last = Integer.valueOf(ip.substring(ip.lastIndexOf(".")+1,ip.length()));return last % ips.size();}//请求//注意,这里和来访ip是有关系的,采用一个参数,表示当前的来访ipvoid request(String ip){//下标int i = hash(ip);System.out.println(ip+"-->"+ips.get(i));}public static void main(String[] args) {Hash hash = new Hash("192.168.0.1,192.168.0.2");for (int i = 1; i < 10; i++) {//模拟请求的来源ipString ip = "192.168.0."+ i;hash.request(ip);}hash.addnode("192.168.0.3");for (int i = 1; i < 10; i++) {//模拟请求的来源ipString ip = "192.168.0."+ i;hash.request(ip);}hash.remove("192.168.0.2");for (int i = 1; i < 10; i++) {//模拟请求的来源ipString ip = "192.168.0."+ i;hash.request(ip);}}}

初始化后,只有1,2,下标为末尾ip取余数,多次运行,响应的机器不变,实现了会话保持。
3加入后,重新hash,机器分布发生变化。
2被移除后,原来hash到2的请求被重新定位给3响应。

3、一致性哈希

源地址hash算法,让某些请求固定的落在对应的服务器上。这样可以解决会话信息保留的问题。

同时,标准的hash,如果机器节点数发生变更。那么请求会被重新hash,打破了原始的设计初衷,怎么解决呢?答案就是一致性hash。

(1)原理

以4台机器为例,一致性hash的算法如下:
首先求出各个服务器的哈希值,并将其配置到0~232的圆上;
然后采用同样的方法求出存储数据的键的哈希值,也映射圆上;
从数据映射到的位置开始顺时针查找,将数据保存到找到的第一个服务器上;
如果到最大值仍然找不到,就取第一个。这就是为啥形象的称之为环。
在这里插入图片描述
添加节点:
在这里插入图片描述
删除节点原理雷同

(2)特性

单调性(Monotonicity):单调性是指如果已经有一些请求通过哈希分派到了相应的服务器进行处理,又有新的服务器加入到系统中时候,应保证原有的请求可以被映射到原有的或者新的服务器中去,而不会被映射到原来的其它服务器上去。

分散性(Spread):分布式环境中,客户端请求时可能只知道其中一部分服务器,那么两个客户端看到不同的部分,并且认为自己看到的都是完整的hash环,那么问题来了,相同的key可能被路由到不同服务器上去。以上图为例,加入client1看到的是1,4;client2看到的是2,3;那么2-4之间的key会被俩客户端重复映射到3,4上去。分散性反应的是这种问题的严重程度。

平衡性(Balance):平衡性是指客户端hash后的请求应该能够分散到不同的服务器上去。一致性hash可以做到尽量分散,但是不能保证每个服务器处理的请求的数量完全相同。这种偏差称为hash倾斜。如果节点的分布算法设计不合理,那么平衡性就会收到很大的影响。

(3)优化

增加虚拟节点可以优化hash算法,使得切段和分布更细化。即实际有m台机器,但是扩充n倍,在环上放置m*n个,那么均分后,key的段会分布更细化。
在这里插入图片描述

(4)Java实现一致性哈希算法

import java.util.Random;
import java.util.SortedMap;
import java.util.TreeMap;/*** 不带虚拟节点的一致性Hash算法*/
public class ConsistentHashingWithoutVirtualNode {//服务器列表private static String[] servers = { "192.168.0.0", "192.168.0.1","192.168.0.2", "192.168.0.3", "192.168.0.4" };//key表示服务器的hash值,value表示服务器private static SortedMap<Integer, String> serverMap = new TreeMap<Integer, String>();static {for (int i=0; i<servers.length; i++) {int hash = getHash(servers[i]);//理论上,hash环的最大值为2^32//这里为做实例,将ip末尾作为上限也就是254//那么服务器是0-4,乘以60后可以均匀分布到 0-254 的环上去//实际的请求ip到来时,在环上查找即可hash *= 60;System.out.println("add " + servers[i] + ", hash=" + hash);serverMap.put(hash, servers[i]);}}//查找节点private static String getServer(String key) {int hash = getHash(key);//得到大于该Hash值的所有serverSortedMap<Integer, String> subMap = serverMap.tailMap(hash);if(subMap.isEmpty()){//如果没有比该key的hash值大的,则从第一个node开始Integer i = serverMap.firstKey();//返回对应的服务器return serverMap.get(i);}else{//第一个Key就是顺时针过去离node最近的那个结点Integer i = subMap.firstKey();//返回对应的服务器return subMap.get(i);}}//运算hash值//该函数可以自由定义,只要做到取值离散即可//这里取ip地址的最后一节private static int getHash(String str) {String last = str.substring(str.lastIndexOf(".")+1,str.length());return Integer.valueOf(last);}public static void main(String[] args) {//模拟5个随机ip请求for (int i = 0; i < 5; i++) {String ip = "192.168.0."+ new Random().nextInt(254);System.out.println(ip +" ---> "+getServer(ip));}//将5号服务器加到2-3之间,取中间位置,150System.out.println("add 192.168.0.5,hash=150");serverMap.put(150,"192.168.0.5");//再次发起5个请求for (int i = 0; i < 5; i++) {String ip = "192.168.0."+ new Random().nextInt(254);System.out.println(ip +" ---> "+getServer(ip));}}
}

4台机器加入hash环
模拟请求,根据hash值,准确调度到下游节点
添加节点5,key取150
再次发起请求

五、加权轮询(WRR)算法

1、概述

WeightRoundRobin,轮询只是机械的旋转,加权轮询弥补了所有机器一视同仁的缺点。在轮询的基础上,初始化时,机器携带一个比重

2、Java实现加权轮询算法

维护一个链表,每个机器根据权重不同,占据的个数不同。轮询时权重大的,个数多,自然取到的次数变大。举个例子:a,b,c 三台机器,权重分别为4,2,1,排位后会是a,a,a,a,b,b,c,每次请求时,从列表中依次取节点,下次请求再取下一个。到末尾时,再从头开始。

但是这样有一个问题:机器分布不够均匀,扎堆出现了…

解决:为解决机器平滑出现的问题,nginx的源码中使用了一种平滑的加权轮询的算法,规则如下:
每个节点两个权重,weight和currentWeight,weight永远不变是配置时的值,current不停变化;
变化规律如下:选择前所有current += weight,选current最大的响应,响应后让它的current -= total。
在这里插入图片描述
统计:a=4,b=2,c=1 且分布平滑均衡

public class WRR {//所有节点的列表ArrayList<Node> list ;//总权重int total;//初始化节点列表public WRR(String nodes){String[] ns = nodes.split(",");list = new ArrayList<>(ns.length);for (String n : ns) {String[] n1 = n.split("#");int weight = Integer.valueOf(n1[1]);list.add(new Node(n1[0],weight));total += weight;}}//获取当前节点Node getCurrent(){//执行前,current加权重for (Node node : list) {node.currentWeight += node.weight;}//遍历,取权重最高的返回Node current = list.get(0);int i = 0;for (Node node : list) {if (node.currentWeight > i){i = node.currentWeight;current = node;}}return current;}//响应void request(){//获取当前节点Node node = this.getCurrent();//第一列,执行前的currentSystem.out.print(list.toString()+"---");//第二列,选中的节点开始响应System.out.print(node.name+"---");//响应后,current减掉totalnode.currentWeight -= total;//第三列,执行后的currentSystem.out.println(list);}public static void main(String[] args) {WRR wrr = new WRR("a#4,b#2,c#1");//7次执行请求,看结果for (int i = 0; i < 7; i++) {wrr.request();}}class Node{int weight,currentWeight; // 权重和currentString name;public Node(String name,int weight){this.name = name;this.weight = weight;this.currentWeight = 0;}@Overridepublic String toString() {return String.valueOf(currentWeight);}}
}

六、加权随机(WR)算法

1、概述

WeightRandom,机器随机被筛选,但是做一组加权值,根据权值不同,选中的概率不同。在这个概念上,可以认为随机是一种等权值的特殊情况。

2、Java实现加权随机算法

设计思路依然相同,根据权值大小,生成不同数量的节点,节点排队后,随机获取。这里的数据结构主要涉及到随机的读取,所以优选为数组。

与随机相同的是,同样为数组随机筛选,不同在于,随机只是每台机器1个,加权后变为多个。

public class WR {//所有节点的列表ArrayList<String> list ;//初始化节点列表public WR(String nodes){String[] ns = nodes.split(",");list = new ArrayList<>();for (String n : ns) {String[] n1 = n.split("#");int weight = Integer.valueOf(n1[1]);for (int i = 0; i < weight; i++) {list.add(n1[0]);}}}void request(){//下标,随机数,注意因子int i = new Random().nextInt(list.size());System.out.println(list.get(i));}public static void main(String[] args) {WR wr = new WR("a#2,b#1");for (int i = 0; i < 9; i++) {wr.request();}}}

运行9次,a,b交替出现,a=6,b=3,满足2:1比例
注意!既然是随机,就存在随机性,不见得每次执行都会严格比例。样本趋向无穷时,比例约准确

七、最小连接数(LC)算法

1、概述

LeastConnections,即统计当前机器的连接数,选最少的去响应新的请求。前面的算法是站在请求维度,而最小连接数是站在机器的维度。

2、Java实现最小连接数算法

定义一个链接表记录机器的节点id和机器连接数量的计数器。内部采用最小堆做排序处理,响应时取堆顶节点即是最小连接数。

public class LC {//节点列表Node[] nodes;//初始化节点,创建堆// 因为开始时各节点连接数都为0,所以直接填充数组即可LC(String ns){String[] ns1 = ns.split(",");nodes = new Node[ns1.length+1];for (int i = 0; i < ns1.length; i++) {nodes[i+1] = new Node(ns1[i]);}}//节点下沉,与左右子节点比对,选里面最小的交换//目的是始终保持最小堆的顶点元素值最小//i:要下沉的顶点序号void down(int i) {//顶点序号遍历,只要到1半即可,时间复杂度为O(log2n)while ( i << 1  <  nodes.length){//左子,为何左移1位?回顾一下二叉树序号int left = i<<1;//右子,左+1即可int right = left+1;//标记,指向 本节点,左、右子节点里最小的,一开始取i自己int flag = i;//判断左子是否小于本节点if (nodes[left].get() < nodes[i].get()){flag = left;}//判断右子if (right < nodes.length && nodes[flag].get() > nodes[right].get()){flag = right;}//两者中最小的与本节点不相等,则交换if (flag != i){Node temp = nodes[i];nodes[i] = nodes[flag];nodes[flag] = temp;i = flag;}else {//否则相等,堆排序完成,退出循环即可break;}}}//请求。非常简单,直接取最小堆的堆顶元素就是连接数最少的机器void request(){System.out.println("---------------------");//取堆顶元素响应请求Node node = nodes[1];System.out.println(node.name + " accept");//连接数加1node.inc();//排序前的堆System.out.println("before:"+Arrays.toString(nodes));//堆顶下沉down(1);//排序后的堆System.out.println("after:"+Arrays.toString(nodes));}public static void main(String[] args) {//假设有7台机器LC lc = new LC("a,b,c,d,e,f,g");//模拟10个请求连接for (int i = 0; i < 10; i++) {lc.request();}}class Node{//节点标识String name;//计数器AtomicInteger count = new AtomicInteger(0);public Node(String name){this.name = name;}//计数器增加public void inc(){count.getAndIncrement();}//获取连接数public int get(){return count.get();}@Overridepublic String toString() {return name+"="+count;}}
}

初始化后,堆节点值都为0,即每个机器连接数都为0
堆顶连接后,下沉,堆重新排序,最小堆规则保持成立

八、应用案例

1、nginx upstream

upstream frontend {#源地址haship_hash;server 192.168.0.1:8081;server 192.168.0.2:8082 weight=1 down;server 192.168.0.3:8083 weight=2;server 192.168.0.4:8084 weight=3 backup;server 192.168.0.5:8085 weight=4 max_fails=3 fail_timeout=30s;
}

ip_hash:即源地址hash算法
down:表示当前的server暂时不参与负载
weight:即加权算法,默认为1,weight越大,负载的权重就越大。
backup:备份机器,只有其它所有的非backup机器down或者忙的时候,再请求backup机器。
max_fails:最大失败次数,默认值为1,这里为3,也就是最多进行3次尝试
fail_timeout:超时时间为30秒,默认值是10s。
注意!weight和backup不能和ip_hash关键字一起使用。

2、springcloud ribbon IRule

#设置负载均衡策略 eureka‐application‐service为调用的服务的名称
eureka‐application‐service.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule

RoundRobinRule:轮询
RandomRule:随机
AvailabilityFilteringRule:先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,还有并发的连接数量超过阈值的服务,然后对剩余的服务轮询
WeightedResponseTimeRule:根据平均响应时间计算所有服务的权重,响应时间越快服务权重越大。刚启动时如果统计信息不足,则使用RoundRobinRule策略,等统计信息足够,会切换到该策略
RetryRule:先按照RoundRobinRule的策略,如果获取服务失败则在指定时间内重试,获取可用的服务
BestAvailableRule:会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务
ZoneAvoidanceRule:默认规则,综合判断server所在区域的性能和server的可用性

3、dubbo负载均衡

使用Service注解

@Service(loadbalance = "roundrobin",weight = 100)

RandomLoadBalance: 随机,这种方式是dubbo默认的负载均衡策略
RoundRobinLoadBalance:轮询
LeastActiveLoadBalance:最少活跃次数,dubbo框架自定义了一个Filter,用于计算服务被调用的次数
ConsistentHashLoadBalance:一致性hash

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/34495.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

198、仿真-基于51单片机函数波形发生器调幅度频率波形Proteus仿真(程序+Proteus仿真+原理图+流程图+元器件清单+配套资料等)

毕设帮助、开题指导、技术解答(有偿)见文未 目录 一、硬件设计 二、设计功能 三、Proteus仿真图 四、原理图 五、程序源码 资料包括&#xff1a; 需要完整的资料可以点击下面的名片加下我&#xff0c;找我要资源压缩包的百度网盘下载地址及提取码。 方案选择 单片机的选…

Leetcode-每日一题【剑指 Offer 27. 二叉树的镜像】

题目 请完成一个函数&#xff0c;输入一个二叉树&#xff0c;该函数输出它的镜像。 例如输入&#xff1a; 4 / \ 2 7 / \ / \ 1 3 6 9 镜像输出&#xff1a; 4 / \ 7 2 / \ / \ 9 6 3 1 示例 1&#xff1a; 输入&#xff1a;root [4,2,…

(vue)获取对象的键遍历,同时循环el-tab页展示key及内容

(vue)获取对象的键遍历&#xff0c;同时循环el-tab页展示key及内容 效果&#xff1a; 数据结构&#xff1a; "statusData": {"订购广度": [ {"id": 11, "ztName": "广", …

YAPi在线接口文档简单案例(结合Vue前端Demo)

在前后端分离开发中&#xff0c;我们都是基于文档进行开发&#xff0c;那前端人员有时候无法马上拿到后端的数据&#xff0c;该怎么办&#xff1f;我们一般采用mock模拟伪造数据直接进行测试&#xff0c;本篇文章主要介绍YApi在线接口文档的简单使用&#xff0c;并结合Vue的小d…

[保研/考研机试] KY183 素数 北京航空航天大学复试上机题 C++实现

题目链接&#xff1a; 素数https://www.nowcoder.com/share/jump/437195121691718444910 描述 输入一个整数n(2<n<10000)&#xff0c;要求输出所有从1到这个整数之间(不包括1和这个整数)个位为1的素数&#xff0c;如果没有则输出-1。 输入描述&#xff1a; 输入有多…

vue3+element-plus点击列表中的图片预览时,图片被表格覆盖

文章目录 问题解决 问题 视觉 点击图片进行预览&#xff0c;但还能继续选中其他的图片进行预览&#xff0c;鼠标放在表格上&#xff0c;那一行表格也会选中&#xff0c;如图所示第一行的效果。 代码 <el-table-column prop"id" label"ID" width"…

云原生K8S------Yaml文件详解

目录 一&#xff1a;K8S支持的文件格式 1&#xff0c;yaml和json的主要区别 2&#xff0c;YAML语言格式 二&#xff1a;yuml 1、查看 api 资源版本标签 2、写一个yaml文件demo 3、创建service服务对外提供访问并测试 4、详解k8s中的port 三&#xff1a;文件生成 1、kubec…

Vue2到3 Day5 全套学习内容,众多案例上手(内付源码)

简介&#xff1a; Vue2到3 Day1-3 全套学习内容&#xff0c;众多案例上手&#xff08;内付源码&#xff09;_星辰大海1412的博客-CSDN博客本文是一篇入门级的Vue.js介绍文章&#xff0c;旨在帮助读者了解Vue.js框架的基本概念和核心功能。Vue.js是一款流行的JavaScript前端框架…

类与对象(加深)

目录 1.类的6个默认成员函数 2. 构造函数 2.1 概念 2.2 特性 3.析构函数 3.1 概念 3.2 特性 4. 拷贝构造函数 4.1 概念 4.2 特征 5.赋值运算符重载 5.1 运算符重载 5.2 赋值运算符重载 6.const成员 7.取地址及const取地址操作符重载 1.类的6个默认成员函数 如果…

Mysql 和Oracle的区别

、mysql与oracle都是关系型数据库&#xff0c;Oracle是大型数据库&#xff0c;而MySQL是中小型数据库。但是MySQL是开源的&#xff0c;但是Oracle是收费的&#xff0c;而且比较贵。 1 2 mysql默认端口&#xff1a;3306&#xff0c;默认用户&#xff1a;root oracle默认端口&…

shell脚本开发

shell脚本语言属于弱类型的语言&#xff0c;无需声明变量类型&#xff0c;直接定义使用 shell语言定义的变量&#xff0c;数据类型默认都是字符串类型 调用历史记录命令&#xff1a;&#xff01; 历史记录id

netty基础与原理

Netty线程模型和Reactor模式 简介&#xff1a;reactor模式 和 Netty线程模型 设计模式——Reactor模式&#xff08;反应器设计模式&#xff09;&#xff0c;是一种基于 事件驱动的设计模式&#xff0c;在事件驱动的应用中&#xff0c;将一个或多个客户的 服务请求分离&#x…

【ARM Cache 系列文章 9 -- ARM big.LITTLE技术】

文章目录 big.LITTLE 技术背景big.LITTLE 技术详解big.LITTLE 硬件要求 big.LITTLE 软件模型CPU MigrationGlobal Task SchedulingGlobal Task Scheduling比CPU Migration的优势 转自&#xff1a;https://zhuanlan.zhihu.com/p/630981648 如有侵权&#xff0c;请联系删除 big.L…

Leetcode 21. 合并两个有序链表

题目描述 题目链接&#xff1a;https://leetcode.cn/problems/merge-two-sorted-lists/description/ 思路 两个链表都是升序链表&#xff0c;新建一个链表&#xff0c;引入伪头节点作为辅助节点&#xff0c;将各节点添加到伪节点之后&#xff0c;再用一个cur节点指向新链表的…

2022年03月 C/C++(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

第1题:双精度浮点数的输入输出 输入一个双精度浮点数,保留8位小数,输出这个浮点数。 时间限制:1000 内存限制:65536 输入 只有一行,一个双精度浮点数。 输出 一行,保留8位小数的浮点数。 样例输入 3.1415926535798932 样例输出 3.14159265 下面是一个使用C语言编写的双精…

51单片机学习--红外遥控(外部中断)

需要利用下面这个红外接收头&#xff0c;OUT口会发出红外信号对应的高低电平&#xff0c;由于发送的速度很快&#xff0c;所以需要把OUT引脚接在外部中断引脚上&#xff0c;当OUT一旦产生下降沿&#xff0c;马上进中断&#xff0c;这样响应会更及时。 外部中断引脚位于P3_2和P…

全球八分之一的河流受到缺氧影响

一项全球研究发现&#xff0c;世界各地河流中的溶解氧含量低得危险。缺氧的真实发生率可能更高。 小型、低梯度的城市河流&#xff0c;例如图中北卡罗来纳州的那条河流&#xff0c;是最容易缺氧的河流之一。图片来源&#xff1a;乔安娜布拉扎克 2023 年 3 月&#xff0c;《卫报…

大脑营行|“福安市华龙教育基金”支持家乡教育事业发展

8月8日&#xff0c;福安市松罗中学举行“福安市华龙教育基金”中考奖学金颁发仪式。福安市松罗乡党委书记钟文、乡长郑仁寿、福安市人民政府教育督导室副科级督导员&#xff08;片区领导&#xff09;陈秦、校长张明亮、各村支部书记、家长代表、受奖学生&#xff0c;校领导班子…

@RequestHeader使用

RequestHeader 请求头参数的设置 GetMapping("paramTest/requestHeader")public String requestHeaderTest(RequestHeader("name") String name){return name;} 在Postman的Headers中添加请求头参数&#xff0c;不过貌似不能加中文

百川智能发布首个530亿参数闭源大模型,今年追上GPT-3.5

4月官宣创业&#xff0c;6月15日发布第一款7B开源模型&#xff0c;7月11日发布第二款13B、130亿参数开源模型。 平均保持2个月一个版本发布速度&#xff0c;8月8日&#xff0c;百川智能发布了创业以来的首个530亿参数闭源大模型——Baichuan-53B&#xff08;以下简称“53B”&a…