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就指向新创建的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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

面试笔记:Android 架构岗,一次4小时4面的体验

作者&#xff1a;橘子树 此次面试一共4面4小时&#xff0c;中间只有几分钟间隔。对持续的面试状态考验还是蛮大的。 关于面试的心态&#xff0c;保持悲观的乐观主义心态比较好。面前做面试准备时保持悲观&#xff0c;尽可能的做足准备。面后积极做复盘&#xff0c;乐观的接受最…

【MongoDB】数据库、集合、文档常用CRUD命令

目录 一、数据库操作 1、创建数据库操作 2、查看当前有哪些数据库 3、查看当前在使用哪个数据库 4、删除数据库 二、集合操作 1、查看有哪些集合 2、删除集合 3、创建集合 三、文档基本操作 1、插入数据 2、查询数据 3、删除数据 4、修改数据 四、文档分页查询 …

Selenium之css怎么实现元素定位?

世界上最远的距离大概就是明明看到一个页面元素站在那里&#xff0c;但是我却定位不到&#xff01;&#xff01; Selenium定位元素的方法有很多种&#xff0c;像是通过id、name、class_name、tag_name、link_text等等&#xff0c;但是这些方法局限性太大&#xff0c; 随着自动…

PS透明屏,在科技展示中,有哪些优点展示?

PS透明屏是一种新型的显示技术&#xff0c;它将传统的显示屏幕与透明材料相结合&#xff0c;使得屏幕能够同时显示图像和透过屏幕看到背后的物体。 这种技术在商业展示、广告宣传、产品展示等领域有着广泛的应用前景。 PS透明屏的工作原理是利用透明材料的特性&#xff0c;通…

旷视科技AIoT软硬一体化走向深处,生态和大模型成为“两翼”?

齐奏AI交响曲的当下&#xff0c;赛道玩家各自精彩。其中&#xff0c;被称作AI四小龙的商汤科技、云从科技、依图科技、旷视科技已成长为业内标杆&#xff0c;并积极追赶新浪潮。无论是涌向二级市场还是布局最新风口大模型&#xff0c;AI四小龙谁都不甘其后。 以深耕AIoT软硬一…

机器学习-自定义Loss函数

1、简介 机器学习框架中使用自定义的Loss函数&#xff0c; 2、应用 &#xff08;1&#xff09;sklearn from sklearn.metrics import max_error from sklearn.metrics import make_scorer from sklearn.model_selection import cross_val_score from sklearn.linear_model …

腾讯云标准型CVM云服务器详细介绍

腾讯云CVM服务器标准型实例的各项性能参数平衡&#xff0c;标准型云服务器适用于大多数常规业务&#xff0c;例如&#xff1a;web网站及中间件等&#xff0c;常见的标准型云服务器有CVM标准型S5、S6、SA3、SR1、S5se等规格&#xff0c;腾讯云服务器网来详细说下云服务器CVM标准…

Ubuntu22.04安装docker

在ubuntu22.04上安装docker还是比较容易的&#xff0c;之前在公司的centos6上边装docker&#xff0c;那才真是一言难尽呀&#xff0c;废话不多说&#xff0c;开始安装 1、更新包管理器 apt update 2、安装必要的软件包&#xff0c;以便允许 apt 使用 HTTPS 仓库 sudo apt i…

手撕Java集合——链表

链表 一、链表概念特性二、不带头单向非循环链表实现&#x1f351;1、定义结点&#x1f351;2、打印链表&#x1f351;3、使用递归逆序打印链表&#x1f351;4、头插&#x1f351;5、尾插&#x1f351;6、指定位置插入&#x1f351;7、查找是否包含关键字key是否在单链表当中&a…

多传感器融合相关技术

重要说明&#xff1a;本文从网上资料整理而来&#xff0c;仅记录博主学习相关知识点的过程&#xff0c;侵删。 一、参考资料 多传感器融合定位学习 深蓝-多传感器定位融合 深蓝学院 多传感器融合定位 作业 多传感器融合详解 二、相关介绍 1. 毫米波雷达&#xff08;Radar&a…

R语言4_安装BayesSpace

环境Ubuntu22/20, R4.1 你可能会报错说你的R语言版本没有这个库&#xff0c;但其实不然。这是一个在Bioconductor上的库。 同时我也碰到了这个问题&#xff0c;ERROR: configuration failed for package systemfonts’等诸多类似问题&#xff0c;下面的方法可以一并解决。 第…

790. 多米诺和托米诺平铺

题目描述&#xff1a; 主要思路&#xff1a; class Solution { public:int numTilings(int n) {long long f[n][4],mod1e97;f[0][0]1;f[0][1]f[0][2]0;f[0][3]1;for(int i1;i<n;i){f[i][0]f[i-1][3];f[i][1] (f[i-1][0]f[i-1][2])%mod;f[i][2] (f[i-1][0]f[i-1][1])%mod;f…

力扣221.最大正方形(动态规划)

思路&#xff1a; 思路&#xff1a;从[0,0]元素开始&#xff0c;计算每个元素对应其与[0,0]之间矩阵块中最大正方形边长情况&#xff1a;1&#xff09;matrix [ i , j ] ‘0’ --> 元素对应的最大正方形为0。情况&#xff1a;2&#xff09;matrix [ i , j ] ‘1’ -->…

中级课程-SSRF(CSRF进阶)

文章目录 成因危害挖掘 成因 危害 挖掘

详解JAVA远程debug

目录 1.什么是远程debug&#xff1f; 2.远程debug普通JAVA程序 环境 测试程序 程序启动指令 编译器配置 3.远程debug JAVA Web程序 4.远程debug spring boot程序 1.什么是远程debug&#xff1f; 远程debug&#xff0c;也就是可以在本地debug远端部署的程序&#xff0c…

界面控件DevExpress WPF Chart组件——拥有超快的数据可视化库!

DevExpress WPF Chart组件拥有超大的可视化数据集&#xff0c;并提供交互式仪表板与高性能WPF图表库。DevExpress Charts提供了全面的2D / 3D图形集合&#xff0c;包括数十个UI定制和数据分析/数据挖掘选项。 PS&#xff1a;DevExpress WPF拥有120个控件和库&#xff0c;将帮助…

快速上手PyCharm指南

PyCharm简介 PyCharm是一种Python IDE&#xff08;Integrated Development Environment&#xff0c;集成开发环境&#xff09;&#xff0c;带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具&#xff0c;比如调试、语法高亮、项目管理、代码跳转、智能提示、自动…

Fabric系列 - 知识点整理

知识点 源码编译 主机编译 容器编译 手动部署(docker-compose) 单peer 多peer 中途加peer 多主机多peer 链码 语法, 接口 (go版) 命令行调用 ca server 在DApp中使用SDK调用 (js版) 部署的几个阶段 部署1排序和1节点, 1组织1通道 光部署能Dapp 带ca server (每个组织一个)…

CI/CD—K8S 基本理解与部署

1 K8S 是什么 Kubernetes 是一款容器的编排调度工具&#xff0c;来源于 Google 开源的 Brog 系统。Kubernetes简称K8S&#xff0c;是用8代替8个字符 “ubernete” 而成的缩写&#xff0c;用于管理云平台中多个主机上的容器化的应用&#xff0c;Kubernetes 的目标是让部署容器化…

【javaweb】学习日记Day1 - HTML CSS入门

目录 一、图片标签 ① 绝对路径 1.绝对磁盘路径 2.绝对网络路径 ② 相对路径 &#xff08;推荐&#xff09; 二、标题标签 三、水平线标签 四、标题样式 1、CSS引入样式 ① 行内样式 ② 内嵌样式 ③ 外嵌样式 2、CSS选择器 ① 元素选择器 ② id选择器 ③…