Nginx 限流算法大揭秘

news2024/11/20 6:29:48

博主介绍: ✌博主从事应用安全和大数据领域,有8年研发经验,5年面试官经验,Java技术专家✌

Java知识图谱点击链接:体系化学习Java(Java面试专题)

💕💕 感兴趣的同学可以收藏关注下不然下次找不到哟💕💕

在这里插入图片描述

文章目录

  • 1、什么是 Nginx 限流算法
  • 2、漏桶算法
  • 3、令牌桶算法
  • 4、计数器算法
  • 5、滑动窗口算法

1、什么是 Nginx 限流算法

Nginx 有多种限流算法,以下是其中几种:

  1. 漏桶算法
    漏桶算法是一种比较简单的限流算法。它的原理是将请求放入一个固定容量的漏桶中,然后以固定的速率流出。当请求到来时,如果漏桶已满,则请求被拒绝。漏桶算法可以平滑限制请求的流量,但是对于突发流量无法应对。

  2. 令牌桶算法
    令牌桶算法也是一种常用的限流算法。它的原理是维护一个固定容量的令牌桶,每个请求需要消耗一个令牌才能被处理。当令牌桶中没有足够的令牌时,请求被拒绝。令牌桶算法可以应对突发流量,并且可以设置令牌桶的填充速率和最大容量。

  3. 计数器算法
    计数器算法是一种比较简单的限流算法。它的原理是在一定时间内统计请求的数量,如果超过了设定的阈值,则拒绝请求。计数器算法可以快速应对突发流量,但是对于长时间的流量控制不够精确。

  4. 滑动窗口算法
    滑动窗口算法是一种比较常用的限流算法。它的原理是维护一个固定大小的窗口,记录在窗口时间内的请求数量。当请求到来时,将其加入窗口,并计算窗口内的请求总数。如果请求总数超过了设定的阈值,则拒绝请求。滑动窗口算法可以平滑限制请求的流量,并且可以根据实际情况动态调整窗口大小。

2、漏桶算法

漏桶算法是一种常用的限流算法,它的原理是将请求放入一个固定容量的漏桶中,然后以固定的速率流出。当请求到来时,如果漏桶已满,则请求被拒绝。漏桶算法可以平滑限制请求的流量,但是对于突发流量无法应对。

漏桶算法的实现方式为,将请求放入一个固定容量的漏桶中,然后以固定的速率流出。当请求到来时,如果漏桶未满,则将请求放入漏桶中,否则拒绝请求。漏桶中的请求以固定的速率流出,可以平滑限制请求的流量。漏桶算法可以应对流量波动较小的情况,但是对于突发流量无法应对。

我们接下来用 java 实现一个漏桶算法,代码如下:

package com.pany.camp.limiting;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @description: 漏桶算法
 * @copyright: @Copyright (c) 2022
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0
 * @createTime: 2023-06-24 20:38
 */
public class LeakyBucket {
    private final long capacity; // 漏桶容量
    private final long rate;     // 漏水速率,单位:个/秒
    private AtomicLong water;    // 当前水量
    private long lastTime;       // 上一次漏水时间

    public LeakyBucket(long capacity, long rate) {
        this.capacity = capacity;
        this.rate = rate;
        this.water = new AtomicLong(0);
        this.lastTime = System.currentTimeMillis();
    }

    // 判断桶中是否能够容纳指定数量的水
    public synchronized boolean tryConsume(long num) {
        // 先漏水
        long now = System.currentTimeMillis();
        long leaked = (now - lastTime) * rate / 1000;
        if (leaked > 0) {
            water.set(Math.max(0, water.get() - leaked));
            lastTime = now;
        }
        // 再加水
        if (num <= capacity - water.get()) {
            water.addAndGet(num);
            return true;
        } else {
            return false;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        LeakyBucket bucket = new LeakyBucket(10, 2); // 漏桶容量为10,漏水速率为2个/秒
        for (int i = 0; i < 200; i++) { // 模拟200个请求
            if (bucket.tryConsume(1)) {
                System.out.println("处理请求 " + i);
            } else {
                System.out.println("请求 " + i + " 被限流");
            }
            TimeUnit.MILLISECONDS.sleep(100); // 每个请求间隔100毫秒
        }
    }
}

以下是上面的输出:

Connected to the target VM, address: '127.0.0.1:61851', transport: 'socket'
处理请求 0
处理请求 1
处理请求 2
处理请求 3
处理请求 4
处理请求 5
处理请求 6
处理请求 7
处理请求 8
处理请求 9
处理请求 10
处理请求 11
请求 12 被限流
请求 13 被限流
请求 14 被限流
处理请求 15
请求 16 被限流
请求 17 被限流
请求 18 被限流
请求 19 被限流
处理请求 20
.....

理解了漏桶算法之后呢,我们学习一下如何配置。
在 Nginx 中配置漏桶算法可以通过 ngx_http_limit_req_module模块实现。该模块可以限制并发请求的数量和请求的速率,从而防止服务器被过多的请求压垮。

以下是一个使用漏桶算法限制请求速率的 Nginx 配置示例:

http {
    limit_req_zone $binary_remote_addr zone=limit:10m rate=2r/s;
    server {
        listen 80;
        server_name example.com;
        location / {
            limit_req zone=limit burst=5;
            # 其他配置
        }
    }
}

在上面的配置中, limit_req_zone 指令用于定义一个名为 limit 的内存共享区域,用于存储客户端 IP 地址的请求信息。该指令的参数说明如下:

  • $binary_remote_addr :使用客户端 IP 地址作为键值。
  • zone=limit:10m :定义名为 limit 的内存共享区域,大小为 10MB。
  • rate=2r/s :设置漏桶的速率为 2 个请求/秒。

在 server 块中, listen 指令用于指定监听的端口和主机名, server_name 指令用于指定服务器的域名。 location 块用于指定请求的处理方式,其中的 limit_req 指令用于限制请求速率。该指令的参数说明如下:

  • zone=limit :使用名为 limit 的内存共享区域存储客户端请求信息。
  • burst=5 :设置漏桶的容量为 5 个请求。

在上面的配置中,如果客户端发送的请求速率超过了 2 个请求/秒,则会被限制,直到漏桶中的请求数量小于等于 5。

3、令牌桶算法

令牌桶算法是一种常用的流量控制算法,可以用于限制请求的速率。它的原理是通过令牌桶来控制请求的访问速率,每个请求需要消耗一个令牌,而令牌桶以一定的速率生成令牌,当令牌桶中没有令牌时,请求将被限制。

令牌桶算法中,令牌桶是一个固定容量的桶,其中包含一定数量的令牌。每个令牌代表一个请求的访问权限。令牌桶以一定的速率生成令牌,当请求到来时,如果令牌桶中有令牌,则允许请求访问,并消耗一个令牌;如果令牌桶中没有令牌,则请求被限制。

令牌桶算法可以用于限制请求的速率,防止服务器被过多的请求压垮。它也可以用于限制用户的访问频率,防止恶意用户对服务器进行攻击。

我们接下来用 java 实现一个令牌桶算法,代码如下:

package com.pany.camp.limiting;

import java.util.concurrent.atomic.AtomicInteger;

/**
 *
 * @description:  令牌桶算法
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-24 20:45
 */
public class TokenBucket {

    private final int capacity; // 令牌桶的容量
    private final int rate; // 令牌生成速率
    private final AtomicInteger tokens; // 当前令牌数
    private long timestamp; // 上次更新时间

    public TokenBucket(int capacity, int rate) {
        this.capacity = capacity;
        this.rate = rate;
        this.tokens = new AtomicInteger(capacity);
        this.timestamp = System.currentTimeMillis();
    }

    public synchronized boolean acquire() {
        // 计算时间间隔
        long now = System.currentTimeMillis();
        long interval = now - timestamp;
        // 计算新生成的令牌数
        int newTokens = (int) (interval * rate / 1000);
        if (newTokens > 0) {
            tokens.set(Math.min(capacity, tokens.get() + newTokens));
            timestamp = now;
        }
        // 判断是否有足够的令牌
        if (tokens.get() > 0) {
            tokens.decrementAndGet();
            return true;
        } else {
            return false;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        TokenBucket bucket = new TokenBucket(10, 2); // 令牌桶容量为 10,令牌生成速率为 2 个/秒
        for (int i = 0; i < 200; i++) {
            Thread.sleep(100); // 每隔 100 毫秒发送一个请求
            if (bucket.acquire()) {
                System.out.println("请求 " + i + " 被处理");
            } else {
                System.out.println("请求 " + i + " 被限流");
            }
        }
    }
}

在上面的代码中, TokenBucket 类表示一个令牌桶,包含令牌桶的容量、令牌生成速率、当前令牌数和上次更新时间等属性。 acquire 方法用于获取令牌,如果令牌桶中有足够的令牌,则返回 true ,否则返回 false 。

在 acquire 方法中,首先计算时间间隔 interval ,然后根据时间间隔和令牌生成速率计算新生成的令牌数 newTokens 。如果新生成的令牌数大于 0,则更新令牌桶中的令牌数和上次更新时间。最后,判断令牌桶中是否有足够的令牌,如果有,则减少一个令牌并返回 true ,否则返回 false 。

以下是上面的输出:

Connected to the target VM, address: '127.0.0.1:62453', transport: 'socket'
请求 0 被处理
请求 1 被处理
请求 2 被处理
请求 3 被处理
请求 4 被处理
请求 5 被处理
请求 6 被处理
请求 7 被处理
请求 8 被处理
请求 9 被处理
请求 10 被处理
请求 11 被处理
请求 12 被限流
请求 13 被限流
请求 14 被处理
请求 15 被限流
请求 16 被限流
请求 17 被限流
请求 18 被限流
请求 19 被处理
请求 20 被限流
......

理解了漏桶算法之后呢,我们学习一下如何配置。

在 Nginx 中配置令牌桶算法可以使用 ngx_http_limit_req_module 模块。该模块提供了限制请求速率的功能,包括基于令牌桶算法的限速。

以下是一个简单的 Nginx 配置示例,使用令牌桶算法限制每个 IP 地址的请求速率为 10 个/秒:

http {
    limit_req_zone $binary_remote_addr zone=rate-limit:10m rate=10r/s;
    server {
        listen 80;
        server_name example.com;
        location / {
            limit_req zone=rate-limit burst=20 nodelay;
            proxy_pass http://backend;
        }
    }
}

Nginx 中的令牌桶算法和漏桶算法在配置上非常相似,这是因为它们都是基于限速的算法,本质上都是通过控制请求的速率来保护服务器或应用程序。虽然它们在实现细节上有所不同,但在 Nginx 的实现中,它们都使用了 ngx_http_limit_req_module 模块,因此配置方式类似。

具体来说,两种算法的区别在于令牌桶算法是按照固定速率生成令牌,然后根据令牌数量来控制请求的速率;而漏桶算法是按照固定速率处理请求,然后根据漏桶中的水量来控制请求的速率。在 Nginx 中, ngx_http_limit_req_module 模块提供了 limit_req_zone 和 limit_req 两个指令,它们可以同时支持令牌桶算法和漏桶算法,只需要在配置中指定不同的参数即可。

4、计数器算法

计数器算法是一种常用的限速算法,它通过计数器来记录请求的数量,然后根据计数器的值来控制请求的速率。计数器算法的实现方式有很多种,其中比较常见的是以下两种:

  • 固定窗口计数器算法:将请求的数量累加到计数器中,然后每隔固定的时间窗口,将计数器清零。在每个时间窗口内,只允许处理一定数量的请求,超出限制的请求会被丢弃或延迟处理。
  • 滑动窗口计数器算法:将时间分为若干个时间段,然后分别记录每个时间段内的请求数量。在每个时间段内,只允许处理一定数量的请求,超出限制的请求会被丢弃或延迟处理。与固定窗口计数器算法相比,滑动窗口计数器算法可以更精确地控制请求的速率,但同时也需要更多的计算和存储资源。
    计数器算法可以应用于各种场景,例如限制 API 接口的请求速率、限制爬虫的访问频率等。它的实现简单,效率高,因此被广泛应用。

我们接下来用 java 实现一个计数器算法,代码如下:

package com.pany.camp.limiting;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 *
 * @description:  固定窗口计数器算法
 * @copyright: @Copyright (c) 2022 
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0 
 * @createTime: 2023-06-24 21:10
 */
public class FixedWindowCounter {
    private final int limit; // 限制数量
    private final long windowSize; // 窗口时间
    private final AtomicInteger counter; // 计数器
    private final Lock lock; // 锁对象
    private long lastUpdateTime; // 上次更新时间

    public FixedWindowCounter(int limit, long windowSize) {
        this.limit = limit;
        this.windowSize = windowSize;
        this.counter = new AtomicInteger(0);
        this.lock = new ReentrantLock();
        this.lastUpdateTime = System.currentTimeMillis();
    }

    public boolean tryAcquire() {
        lock.lock();
        try {
            long now = System.currentTimeMillis();
            if (now - lastUpdateTime >= windowSize) { // 窗口时间已过,重置计数器
                counter.set(0);
                lastUpdateTime = now;
            }
            if (counter.incrementAndGet() > limit) { // 超过限制数量,返回 false
                return false;
            }
            return true;
        } finally {
            lock.unlock();
        }
    }

    public static void main(String[] args) {
        FixedWindowCounter counter = new FixedWindowCounter(5, 1000);

        // 模拟在 1 秒内进行 10 次请求
        for (int i = 0; i < 10; i++) {
            if (counter.tryAcquire()) {
                System.out.println("请求 " + (i + 1) + " 被处理");
            } else {
                System.out.println("请求 " + (i + 1) + " 被限流");
            }
        }
    }
}

以下是上面的输出:

请求 1 被处理
请求 2 被处理
请求 3 被处理
请求 4 被处理
请求 5 被处理
请求 6 被限流
请求 7 被限流
请求 8 被限流
请求 9 被限流
请求 10 被限流

Process finished with exit code 0

理解了漏桶算法之后呢,我们学习一下如何配置。

  1. 在 http 块中使用 limit_req_zone 指令来定义限制区域,例如:
http {
    limit_req_zone $binary_remote_addr zone=rate-limit:10m rate=10r/s;
}
  1. 在 server 或 location 块中使用 limit_req 指令来应用 FixedWindowCounter 算法,例如:
server {
    listen 80;
    server_name example.com;
    location / {
        limit_req zone=rate-limit burst=20;
        proxy_pass http://backend;
    }
}

其中, rate-limit 表示应用的限制区域, burst 表示允许的突发请求数量。

这样配置后,Nginx 将会对每个 IP 地址在每秒钟最多处理 10 个请求,超过这个数量的请求将会被延迟或拒绝。如果在固定时间窗口内请求量超过了 burst 数量,则会触发限流,直到时间窗口结束。

需要注意的是,FixedWindowCounter 算法的时间窗口是固定的,如果请求量不均匀分布,则可能会出现一些请求在时间窗口开始时被限流,而在时间窗口结束时可以得到处理的情况。因此,如果需要更精确的限流算法,可以考虑使用 RollingWindowCounter 算法。

5、滑动窗口算法

滑动窗口算法是一种用于解决数据流或连续数据的问题的算法。它通常用于计算滑动时间窗口内的数据总和、平均值、最大值、最小值等统计信息,或者在滑动窗口内查找特定的数据子序列。滑动窗口算法的基本思想是维护一个固定大小的滑动窗口,该窗口在数据流中向右滑动,并在每个时间点计算窗口内的数据。具体来说,滑动窗口算法通常使用双指针来维护窗口的起始位置和结束位置,同时使用一个数据结构(如队列、栈、哈希表等)来维护窗口内的数据。在每个时间点,我们将窗口向右滑动一个单位,同时添加新的数据,并从窗口左侧删除旧的数据。这样,我们就可以在滑动窗口内快速地计算各种统计信息或查找特定的数据子序列。

滑动窗口算法通常用于处理实时数据流、日志数据、网络流量等场景,它具有时间复杂度低、空间复杂度小、实现简单等优点。常见的滑动窗口算法包括滑动时间窗口算法、滑动计数窗口算法、滑动平均窗口算法等。

我们接下来用 java 实现一个滑动窗口限流算法,代码如下:

package com.pany.camp.limiting;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @description: 滑动窗口限流算法
 * @copyright: @Copyright (c) 2022
 * @company: Aiocloud
 * @author: pany
 * @version: 1.0.0
 * @createTime: 2023-06-24 21:20
 */
public class SlidingWindow {
    private int windowSize; // 窗口大小
    private int threshold; // 阈值
    private int[] window; // 窗口数组
    private int index; // 窗口指针
    private int count; // 窗口内请求数量

    public SlidingWindow(int windowSize, int threshold) {
        this.windowSize = windowSize;
        this.threshold = threshold;
        this.window = new int[windowSize];
        this.index = 0;
        this.count = 0;
    }

    public synchronized boolean allowRequest() {
        long now = System.currentTimeMillis();
        int currentIndex = (int) (now / 1000 % windowSize);
        if (currentIndex != index) {
            count -= window[currentIndex];
            window[currentIndex] = 0;
            index = currentIndex;
        }
        if (count < threshold) {
            window[index]++;
            count++;
            return true;
        } else {
            return false;
        }
    }

    public static void main(String[] args) {
        SlidingWindow slidingWindow = new SlidingWindow(10, 5);
        for (int i = 0; i < 20; i++) {
            if (slidingWindow.allowRequest()) {
                System.out.println("请求 " + i + " 被处理");
            } else {
                System.out.println("请求 " + i + " 被限制");
            }
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

上面的代码中, SlidingWindow 类表示一个滑动窗口限流器, windowSize 表示窗口大小, threshold 表示阈值, window 表示窗口数组, index 表示窗口指针, count 表示窗口内请求数量。 allowRequest 方法用于判断是否允许进行新的请求,如果窗口内的请求数量小于阈值,就允许请求,并更新窗口内的请求数量和窗口指针;否则就拒绝请求。 main 方法是一个简单的测试方法,循环进行 20 次请求,并输出每个请求是否被允许。

以下是上面的输出:

请求 0 被处理
请求 1 被处理
请求 2 被处理
请求 3 被处理
请求 4 被处理
请求 5 被限制
请求 6 被限制
请求 7 被限制
请求 8 被限制
请求 9 被限制
请求 10 被限制
请求 11 被限制
请求 12 被限制
请求 13 被限制
请求 14 被限制
请求 15 被限制
请求 16 被限制
请求 17 被限制
请求 18 被限制
请求 19 被限制

Process finished with exit code 0

理解了漏桶算法之后呢,我们学习一下如何配置。

在 Nginx 中,可以使用 ngx_http_limit_req_module模块来实现滑动窗口限流算法。该模块可以基于客户端 IP 或请求参数等进行限流,并支持自定义限流阈值和窗口大小等参数。下面是一个简单的滑动窗口限流算法的 Nginx 配置示例,您可以参考一下:


http {
    limit_req_zone $binary_remote_addr zone=rate-limit:10m rate=10r/s;
    server {
        listen 80;
        server_name example.com;
        location / {
            limit_req zone=rate-limit burst=20 nodelay;
            proxy_pass http://backend;
        }
    }
}

上面的配置中, limit_req_zone 指令用于定义限流区域,其中 $binary_remote_addr 表示使用客户端 IP 作为限流键, rate-limit 表示限流区域的名称, 10m 表示限流区域的大小为 10MB, 10r/s 表示限流速率为每秒 10 个请求。 limit_req 指令用于应用限流规则,其中 zone=rate-limit 表示使用名为 rate-limit 的限流区域, burst=20 表示突发请求的数量为 20 个, nodelay 表示不延迟请求,即直接拒绝超出限流阈值的请求。 proxy_pass 指令用于将请求转发到后端服务器。

需要注意的是,上面的示例中使用的是基于客户端 IP 的限流,如果您需要基于其他参数进行限流,可以将 $binary_remote_addr 替换为其他参数,例如 $http_user_agent 表示使用 User-Agent 作为限流键。另外,Nginx 的限流是针对整个服务器的,如果您需要对某个具体的 API 或接口进行限流,可以使用 location 指令来指定。

在这里插入图片描述

💕💕 本文由激流原创,首发于CSDN博客,博客主页 https://blog.csdn.net/qq_37967783?spm=1010.2135.3001.5421
💕💕喜欢的话记得点赞收藏啊

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

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

相关文章

01 | 一条 SQL 查询语句是如何执行的?

以下内容出自 《MySQL 实战 45 讲》 一条 SQL 查询语句是如何执行的&#xff1f; 下面是 MySQL 的基本架构示意图&#xff0c;从中可以清楚地看到 SQL 语句在 MySQL 的各个功能模块中的执行过程。 大体来说&#xff0c;MySQL 可以分为 Server 层和存储引擎层两部分。 Server …

leetcode188. 买卖股票的最佳时机 IV.动态规划-java

买卖股票的最佳时机 IV leetcode188. 买卖股票的最佳时机 IV题目描述 动态规划代码演示 动态规划专题 leetcode188. 买卖股票的最佳时机 IV 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 链接&#xff1a;https://leetcode.cn/problems/best-time-to-buy-and-sell-st…

DatenLord前沿技术分享 No.28

达坦科技专注于打造新一代开源跨云存储平台DatenLord&#xff0c;通过软硬件深度融合的方式打通云云壁垒&#xff0c;致力于解决多云架构、多数据中心场景下异构存储、数据统一管理需求等问题&#xff0c;以满足不同行业客户对海量数据跨云、跨数据中心高性能访问的需求。在本周…

Reentrantreadwritelock应用和原理

目录 一、介绍 二、应用 三、原理 一、介绍 当读操作远远高于写操作时&#xff0c;这时候使用读写锁让读-读可以并发&#xff0c;提高性能 类似于数据库中的共享锁 select...from...lock in share mode 提供一个数据容器类内部分别使用读锁保护数据的read()方法&#x…

Android 9-SystemUI:(1)启动流程

具体分析(以下代码示例&#xff0c;讲解&#xff0c;都是通过&#xff0c;Android9代码来举例&#xff09; SystemUI,其实是可以看作是一个系统级的服务&#xff0c;也就是SystemUIService, SystemUI的服务启动&#xff0c;要从SystemServer.run()方法入手 main 方法里启动了…

JavaWeb小记—响应对象response

目录 响应对象response的原理图 response——响应对象 响应文本数据 响应字节数据 验证码案例 响应状态码 1.http状态返回代码 1xx&#xff08;临时响应&#xff09; 2.http状态返回代码 2xx &#xff08;成功&#xff09; 3.http状态返回代码 3xx &#xff08;重定向…

2023.6.12-6.18 AI行业周刊(第151期):AI创业项目交付部署,困难和机遇并存

这段时间&#xff0c;工作上项目上的事情&#xff0c;开始进入了一个快车道&#xff0c;很多项目开始并行。所以每天白天的时候&#xff0c;被各种事情填充的很满。 加入华勤后从0到1组建的团队&#xff0c;其实本身也是创业属性&#xff0c;从市场->售前->算法->视频…

Godot 4 源码分析 - 练手 - 和谐共生

今天看到一个微信视频&#xff0c;和谐共生&#xff0c;大概效果如下 https://live.csdn.net/v/306826 研究这么长时间的Godot&#xff0c;今天试试能否实现上述效果 粗看一下&#xff0c;这个效果实现分几步&#xff1a; 1. 画圆&#xff0c;并确定多个圆的位置规律 2. 动…

UE4/5动画系列(2.怎么套模板)

目录 大象套模板 动画同步&#xff08;这个在模板里面开同步&#xff09;&#xff1a; 速度限制&#xff1a; 穿墙问题&#xff1a; 在之前我们已经做了一个基础的模板了&#xff1a; UE4/5动画蓝图模板制作和套模板&#xff08;1.模板制作&#xff09;_多方通行8的博客-C…

【计算机组成原理】总线

目录 一、总线概述 二、总线的分类 三、系统总线的结构 四、总线的性能指标 五、总线仲裁 六、总线操作和定时 七、总线标准 一、总线概述 总线&#xff1a;是一组能为多个部件分时共享信息的传送线路 早期计算机外部设备少时大多采用分散连接方式&#xff0c;不易实现…

【C语言初阶】带你轻松玩转所有常用操作符(1)

君兮_的个人主页 勤时当勉励 岁月不待人 C/C 游戏开发 Hello,这里是君兮_&#xff0c;最近要准备期末复习了&#xff0c;可能更新的就不会那么频繁了&#xff0c;下个星期回复正常更新。 操作符详解1 前言一.操作符的分类二.算数操作符三.移位操作符1.二进制表示的三种形式2.…

【C/C++】构造函数与析构函数

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

【话题研究】重塑活力:顺应消费需求变化,PC市场需创新、技术驱动和营销策略更优解

话题研究&#xff1a;大众还需要PC吗&#xff1f;PC市场如何走出寒冬&#xff1f; 1️⃣ PC市场进入寒冬的深层原因2️⃣ PC仍具有独特的优势和不可替代性3️⃣ 创新、定制化和用户体验4️⃣ AI、VR时代带来的新出路 市场调研机构 Canalys数据显示&#xff0c;今年一季度&#…

elastic-job-ui在使用druid作为数据库连接池时作业维度报错

问题说明&#xff1a; 我们项目中使用到了elastic-job&#xff0c;然后自己封装了个sdk&#xff0c;方便使用&#xff0c;里面的数据源配置是常用的druidmysql的组合&#xff0c;在操作中&#xff0c;发现elastic-job-ui可视化控制台会报错无法使用。 深究其原因是因为&#…

返回值封装,异常统一处理优雅解决接口所有问题

在项目整体架构设计的时候&#xff0c;我们经常需要做以下工作&#xff1a; 返回值的统一封装处理&#xff0c;因为只有规范好统一的返回值格式&#xff0c;才能不会给接口使用者带来疑惑和方便前端对接口的统一处理。对异常码进行严格规定&#xff0c;什么错误返回什么码制&a…

ShardingSphere-JDBC 5.1.1 分库分表

分库分表解决的问题 mysql的扩展 mysql并不能完全利用高性能服务器的硬件&#xff0c;当cpu超过24个&#xff0c;内存超过128G时&#xff0c;mysql性能处于平缓&#xff0c;不在上升&#xff0c;所以在一个性能强大的服务器上运行多个实例&#xff0c;才更合理 mysql常见的扩…

java.sql.SQLException: No value specified for parameter 6

异常 java.sql.SQLException: No value specified for parameter 6 原因 sql中定义了6个参数&#xff0c;只传了5个参数

设计模式—“领域规则”

在特定领域中,某些变化虽然频繁,但可以抽象为某种规则。这时候,结合特定领域,将问题抽象为语法规则,从而给出在该领域下的一般性解决方案。 典型模式有:Interpreter Interpreter 动机 在软件构建过程中,如果某一个特定领域的问题比较复杂,类似的结构不断重复出现,…

.NET Microsoft.Extensions.Logging + NLog 记录日志到文件

最近想了解下面向对象开发&#xff0c;选择C# 语言 以及NET6.0 日志是开发中最常用的功能&#xff0c;本文记录下其中日志使用方法&#xff0c;理解不全的地方后续再学习补充 环境 Ubuntu 22.04.2 LTSdotnet 6.0.411 准备工作 # https://learn.microsoft.com/zh-cn/dotnet/c…

2023.6.21AgentGPT部署

在云服务器上使用Docker部署AgentGPT 需要自行提供OpenAI的API Key https://platform.openai.com/account/api-keys 需要自行提供云服务器或者虚拟机 需要自行解决网络的问题&#xff0c;本文中使用的是小喵咪解决网络的问题【需要订阅地址】 文章目录 在云服务器上使用Docker…