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

news2025/1/12 5:58:50

文章目录

  • 一、负载均衡算法概述
  • 二、轮询(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就指向新创建的server
                this.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() {
            @Override
            public 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 {
    // 所有服务ip
    ArrayList<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() {
            @Override
            public 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 {
    // 所有服务ip
    ArrayList<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是有关系的,采用一个参数,表示当前的来访ip
    void 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++) {
            //模拟请求的来源ip
            String ip = "192.168.0."+ i;
            hash.request(ip);
        }

        hash.addnode("192.168.0.3");
        for (int i = 1; i < 10; i++) {
            //模拟请求的来源ip
            String ip = "192.168.0."+ i;
            hash.request(ip);
        }

        hash.remove("192.168.0.2");
        for (int i = 1; i < 10; i++) {
            //模拟请求的来源ip
            String 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值的所有server
		SortedMap<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之间,取中间位置,150
		System.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();
        //第一列,执行前的current
        System.out.print(list.toString()+"---");
        //第二列,选中的节点开始响应
        System.out.print(node.name+"---");
        //响应后,current减掉total
        node.currentWeight -= total;
        //第三列,执行后的current
        System.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; // 权重和current
        String name;
        public Node(String name,int weight){
            this.name = name;
            this.weight = weight;
            this.currentWeight = 0;
        }

        @Override
        public 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");
        //连接数加1
        node.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();
        }

        @Override
        public String toString() {
            return name+"="+count;
        }
    }
}

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

八、应用案例

1、nginx upstream

upstream frontend {
	#源地址hash
	ip_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.coloradmin.cn/o/870440.html

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

相关文章

在Java中对XML的简单应用

XML 数据传输格式1 XML 概述1.1 什么是 XML1.2 XML 与 HTML 的主要差异1.3 XML 不是对 HTML 的替代 2 XML 语法2.1 基本语法2.2 快速入门2.3 组成部分2.3.1 文档声明格式属性 2.3.2 指令&#xff08;了解&#xff09;&#xff1a;结合CSS2.3.3 元素2.3.4 属性**XML 元素 vs. 属…

c++ 学习系列 -- 智能指针

一 为什么引入智能指针&#xff1f;解决了什么问题&#xff1f; C 程序设计中使用堆内存是非常频繁的操作&#xff0c;堆内存的申请和释放都由程序员自己管理。但使用普通指针&#xff0c;容易造成内存泄露&#xff08;忘记释放&#xff09;、二次释放、程序发生异常时内存泄…

Springboot整合RabbitMq,详细步骤

Springboot整合RabbitMq&#xff0c;详细步骤 1 添加springboot-starter依赖2 添加连接配置3 在启动类上添加开启注解EnableRabbit4 创建RabbitMq的配置类&#xff0c;用于创建交换机&#xff0c;队列&#xff0c;绑定关系等基础信息。5 生产者推送消息6 消费者接收消息7 生产者…

闭环控制方法及其应用:优缺点、场景和未来发展

闭环控制是一种基本的控制方法&#xff0c;它通过对系统输出与期望值之间的误差进行反馈&#xff0c;从而调整系统输入&#xff0c;使系统输出更加接近期望值。闭环控制的主要目标是提高系统的稳定性、精确性和鲁棒性。在实际应用中&#xff0c;闭环控制有多种方法&#xff0c;…

开源代码分享(13)—整合本地电力市场与级联批发市场的投标策略(附matlab代码)

1.引言 1.1摘要 本地电力市场是在分配层面促进可再生能源的效率和使用的一种有前景的理念。然而&#xff0c;作为一个新概念&#xff0c;如何设计和将这些本地市场整合到现有市场结构中&#xff0c;并从中获得最大利润仍然不清楚。在本文中&#xff0c;我们提出了一个本地市场…

linux添加磁盘

一、linux虚拟机添加一块新的硬盘 四步&#xff1a; &#xff08;1&#xff09; &#xff08;2&#xff09;为硬盘进行分区 &#xff08;3&#xff09;初始化硬盘分区 &#xff08;4&#xff09;挂载 在虚拟机上添加一块硬盘 (1)、 虚拟机添加一块新的硬盘作为数据盘 (2) ls…

Idea Live Template 功能总结

文章目录 Java自带的template属性模板psf——public static finalpsfi——public static final intpsfi——public static final StringSt——String 方法模板psvm——main方法sout——打印语句iter——for迭代循环fori——for循环 代码块模板if-e —— if elseelse-if 自定义自…

中国首款量子计算机操作系统本源司南 PilotOS正式上线

中国安徽省量子计算工程研究中心近日宣布&#xff0c;中国国产量子计算机操作系统本源司南 PilotOS 客户端正式上线。 如果把量子芯片比喻成人的“心脏”&#xff0c;那么量子计算机操作系统就相当于人的“大脑”&#xff0c;量子计算应用软件则是人的“四肢”。 据安徽省量子…

Linux 终端命令之文件浏览(1) cat

Linux 文件浏览命令 cat, more, less, head, tail&#xff0c;此五个文件浏览类的命令皆为外部命令。 hannHannYang:~$ which cat /usr/bin/cat hannHannYang:~$ which more /usr/bin/more hannHannYang:~$ which less /usr/bin/less hannHannYang:~$ which head /usr/bin/he…

论文总结《Towards Evaluating the Robustness of Neural Networks(CW)》

原文链接 C&W 这篇论文更像是在讲一个优化问题&#xff0c;后面讲述如何针对生成对抗样本的不可解问题近似为一个可解的问题&#xff0c;很有启发。本文后面将总结论文各个部分的内容。 Motivation 文章提出了一个通用的设计生成对抗样本的方法&#xff0c;根据该论文提…

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

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

【C++学习】STL容器——stack和queue

目录 一、stack的介绍和使用 1.1 stack的介绍 1.2 stack的使用 1.3 stack的模拟实现 二、queue的介绍和使用 2.1 queue的介绍 2.2 queue的使用 2.3 queue的模拟实现 三、priority_queue的介绍和使用 3.1 priority_queue的介绍和使用 3.2 priority_queue的使用 3.4 p…

【Powershell 】(Windows下)常用命令 | 命令别名 | 运行Windows命令行工具 | 运行用户程序(vim、gcc、gdb)

微软官方Powershell文档&#xff1a;https://learn.microsoft.com/zh-cn/powershell/ 命令详细说明&#xff0c;在PDF的最后面&#xff1a; 一、Powershell及命令简介1.1 命令格式1.2 命令的别名 二、cmdlet别名三、cmdlet分类介绍3.1 基础命令1. Get-Command2. Get-Help3. S…

[HDLBIts] Exams/m2014 q4j

Implement the following circuit: ("FA" is a full adder) module top_module (input [3:0] x,input [3:0] y, output [4:0] sum);assign sumxy; endmodule

C数据结构与算法——无向图(邻接矩阵) 应用

实验任务 (1) 掌握图的邻接矩阵存储及基本算法&#xff1b; (2) 掌握该存储方式下的DFS和BFS算法。 实验内容 实现图的邻接矩阵存储结构实现基于邻接矩阵的相关算法及遍历算法 实验源码 #include <malloc.h> #include <stdio.h>#define MAXSIZE 1000 #define …

SpringBoot07——VueX

共享组件之间的数据&#xff0c;集中管理 这一部分某人要打ow我就跳过没看了&#xff0c;哼&#xff0c;都怪某人

【机器学习4】构建良好的训练数据集——数据预处理(一)处理缺失值及异常值

数据预处理 &#x1f4ab;数据预处理的重要性&#x1f4ab;处理缺失值⭐️识别表格中的数据⭐️计算每列缺失值的数量⭐️删除含有缺失值的样本或特征⭐️填充缺失值 &#x1f4ab;处理异常值⭐️异常值的鉴别⭐️异常值的处理 &#x1f4ab;将数据集划分为训练数据集和测试数据…

华为网络篇 RIP的Slient-Interface-26

难度1复杂度 1 目录 一、实验原理 二、实验拓扑 三、实验步骤 四、实验过程 总结 一、实验原理 在默认情况下&#xff0c;RIP会在所有的接口泛洪路由更新信息&#xff08;整个路由表&#xff09;&#xff0c;这里有一个问题&#xff0c;当RIP路由器连接的是一个末端网络时…

基层社会治理平台建设方案[113页PPT]

导读&#xff1a;原文《基层社会治理平台建设方案[113页PPT]》&#xff08;获取来源见文尾&#xff09;&#xff0c;本文精选其中精华及架构部分&#xff0c;逻辑清晰、内容完整&#xff0c;为快速形成售前方案提供参考。 完整版领取方式 完整版领取方式&#xff1a; 如需获取完…

Python(八十二)字符串的常用操作——替换与合并

❤️ 专栏简介&#xff1a;本专栏记录了我个人从零开始学习Python编程的过程。在这个专栏中&#xff0c;我将分享我在学习Python的过程中的学习笔记、学习路线以及各个知识点。 ☀️ 专栏适用人群 &#xff1a;本专栏适用于希望学习Python编程的初学者和有一定编程基础的人。无…