当前位置: 首页 > news >正文

LVS-DR模式集群:案例与概念

DR模式(直接路由)

概念

  • Direct Routing,简称DR模式
  • 采用半开放式的网络结构,与TUN模式的结构类似,但内网服务器并不是分散在各地,而是与调度器位于同一个物理网络
  • 负载调度器与内网服务器通过本地网络连接,不需要建立专用的IP隧道
  • 因为调度器只接收外网的请求,内网服务器的响应则是直接由网关路由出去,所以减轻了调度器的压力
  • 针对大规模集群

忽略网关的DR模式工作原理

这里简化工作流程,忽略网关来讲解局域网内数据的转发流程

也就是说目前的场景是:内网中的交换机、后端服务器、调度器

(1)外网客户端发送请求数据包
    • 网络层:源IP地址为客户端IP,目标IP地址为LVS的VIP(Virtual IP)地址
    • 传输层:源IP的一个随机端口。VIP的80端口
    • 数据链路层:源MAC地址是客户端的MAC地址,目标MAC地址是调度器的MAC地址
(2)交换机接收到数据包后
    • 交换机收到数据包后,根据MAC地址表来转发给对应的调度器
    • 交换机将下一跳的源MAC地址是交换机的MAC地址,目标MAC地址修改为调度器的MAC地址,封装成数据帧,然后传递给调度器
(3)调度器转发数据包到后端服务器
    • 调度器将收到的数据包根据调度策略分配给选定的后端服务器
    • 网络层:此时源地址还是客户端的IP地址保持不变,目标IP地址还是VIP
    • 调度器不能转发数据包,而是调度,数据包内的源、目标地址不变
    • 数据链路层:调度器重新封装数据帧,源MAC地址是调度器的MAC地址,目标MAC地址是后端服务器的真实MAC地址
(4)后端服务器处理请求
    • 后端服务器收到请求后去掉帧头部信息解析,进行应答,生成响应的数据包
    • 网络层:此时响应数据包的源IP地址是后端服务器虚拟子 接口绑定的VIP,目标IP地址是客户端的IP
    • 数据链路层:后端服务器重新封装数据帧,源MAC地址是后端服务器的MAC地址,目标MAC地址是客户端的MAC地址
    • (如果不忽略网关的话,目标MAC地址就是网关的内网接口MAC地址)
(5)交换机转发响应给外网客户端
    • 最后,交换机将响应数据包返回给外网客户端
    • 此时源MAC地址是交换机的MAC地址,目标MAC地址是客户端的MAC地址
    • 如果有网关:网关重新封装数据帧,源MAC地址是网关的外网接口MAC地址,目标MAC地址是客户端的MAC地址
注意
IP地址的重要性
  • 源IP地址:在整个通信过程中,源IP地址标识了数据包的发送方,即客户端的地址。这是确保服务器能够正确返回响应的关键。
  • 目标IP地址:目标IP地址则标识了数据包的最终接收方,如调度器或后端服务器的地址。这确保了数据包在网络中正确路由到达目的地。

如果在传输过程中源IP地址被修改,会导致客户端不接受该数据包,从而导致通信失败或安全问题。

数据帧的重新封装
  • 数据帧在每个网络设备之间传输时,会根据下一个设备的MAC地址进行重新封装。这是数据链路层的操作,确保数据能够通过物理网络正常传输。
  • 每次重新封装时,会保留原始的网络层(IP层)信息,包括源和目标IP地址。这样做的目的是确保数据包在经过多个网络设备时,能够继续被正确地路由到下一个目标,直到达到最终的接收方。

DR模式中的关键问题

每个节点的VIP

在LVS-DR负载均衡群集中,负载均衡器与节点服务器都要配置相同的VIP地址

为什么VIP要在每个节点上都配置?

是为了让后端服务器生成的响应报文的源地址始终保持是VIP,客户端请求的是VIP,最后应答的也是VIP,保持一致


后端服务器真实IP接收—VIP应答

后端服务器接收请求用的是自己的真实IP接收的,但是响应请求的源地址用的却是VIP

解决方法

需要在每一个后端服务器设置路由条目

本主机内两个网卡接口的路由

本地回环增加一个子接口

当使用ens33网卡收到报文后,如果访问的是VIP的地址,就交给lo:0去处理报文封装

通过路由条目把下一跳修改为本地的另一个虚拟网卡(lo:0

所以DR模式叫做直接路由


ARP

如果交换机和调度器是第一次通信,就需要发出ARP广播来查找调度器服务器

但是在局域网中调度器和后端服务器具有相同的VIP地址,会造成各服务器ARP通信的混乱

  • 当ARP广播发送到LVS-DR集群时,因为调度器和后端服务器都是连接到相同的网络上,他们都会接收到ARP广播
  • 应该设置只有前端的调度器进行响应。其他后端服务器不响应 该ARP广播
解决方法
  • 对后端服务器进行处理,使其不响应针对VIP的ARP请求
  • 使用虚拟接口lo:0承载VIP地址
  • 设置内核参数arp_ignore=1表示系统只响应目标地址为本地真实IP的ARP请求

IP地址

当交换机第一次与调度器通信后,网关内ARP缓存表存储的是VIP对应调度器的MAC地址

但是到后端服务器发送响应报文给网关时,这个响应报文的源地址还是VIP但是MAC地址就变成了后端服务器的MAC地址

网关接收到响应以后,会发现VIP对应的MAC地址与ARP缓存表记录的信息对不上

此时如果不处理,那么下次再有外网请求转发时就会直接发送给后端服务器,而不是调度器了

解决方法

对后端服务器进行处理,设置内核参数arp_announce=2表示系统不使用IP包的源地址来设置ARP请求的源地址,而选择发送接口的IP地址

设置完参数以后,后端服务器再发送报文的IP地址就不使用VIP作为地址,而是使用自己的真实地址来发送报文,那么网关接收到了报文就不会冲突了

发送ARP请求时,Linux默认使用IP包的源IP地址(VIP)作为ARP请求包中的源IP地址,而不使用发送接口的IP地址

总结

后端服务器的VIP不参与ARP的请求和应答


案例

案例介绍

为了进一步提高网站的负载能力,现在决定扩展现有的网站平台,基于LVS构建负载均衡集群。

考虑到集群的访问效率,准备采用LVS的DR模式,共享存储设备存放在内网中

案例环境

因为本次案例主要针对Linux上的部署操作,所以与外网通信的网关就模拟存在了

主机

操作系统

IP 地址

角色

服务器

CentOS7.9

192.168.10.101

调度器

服务器

CentOS7.9

192.168.10.102

Web服务器

服务器

CentOS7.9

192.168.10.103

Web服务器

服务器

CentOS7.9

192.168.10.104

NFS共享存储

测试机

CentOS7.9

172.16.16.200

客户端,测试机

实验步骤

打开五台Linux虚拟机并全部连接上XShell

基本环境设置

修改主机名

给对应的主机修改主机名,以便区分

# 192.168.10.101
[root@localhost ~]# hostnamectl set-hostname LVS
[root@localhost ~]# bash
# 192.168.10.102
[root@localhost ~]# hostnamectl set-hostname Web01
[root@localhost ~]# bash
# 192.168.10.103
[root@localhost ~]# hostnamectl set-hostname Web02
[root@localhost ~]# bash
# 192.168.10.104
[root@localhost ~]# hostnamectl set-hostname nfs
[root@localhost ~]# bash
# 192.168.10.105
[root@localhost ~]# hostnamectl set-hostname client
[root@localhost ~]# bash

调度器设置

配置VIP

在101(调度器)操作

cd进入存放网卡配置文件的目录下,拷贝出一个子接口网卡配置文件,修改如下几条内容

UUID可以保留,因为这两个IP用到的都是同一个物理网卡,不冲突

[root@lvs ~]# cd /etc/sysconfig/network-scripts/
[root@lvs network-scripts]# cp ifcfg-ens33 ifcfg-ens33:0
[root@lvs network-scripts]# vim ifcfg-ens33:0
IPADDR=192.168.10.172
NAME=ens33:0
DEVICE=ens33:0

保存并退出,重启网络,使用ifconfig查看子接口是否被创建出来了

[root@lvs network-scripts]# systemctl restart network
[root@lvs network-scripts]# ifconfig
ens33:0:inet 192.168.10.172  netmask 255.255.255.0
配置内核参数

调度器并不是转发报文,而是根据调度策略分配,所以在内核配置文件里设置:关闭转发功能

  • net.ipv4.conf.all.send_redirects
    • 是否允许系统重定向功能
    • ICMP重定向消息是用来告知主机在其它子网的更佳路由信息的消息
  • net.ipv4.conf.default.send_redirects
    • 默认是否允许系统重定向功能
    • 如果没有单独为某个接口设置不同的值,那么会使用这个默认值
  • net.ipv4.conf.ens33.send_redirects
    • 针对ens33网络接口的设置,它覆盖了默认值和全局设置,确保对该网络接口禁止发送重定向消息
[root@lvs ~]# vim /etc/sysctl.conf
net.ipv4.conf.all.send_redirects=0
net.ipv4.conf.default.send_redirects=0
net.ipv4.conf.ens33.send_redirects=0

使用sysctl -p来不用重启系统应用内核配置

[root@lvs ~]# sysctl -p
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.ens33.send_redirects = 0
配置调度策略

为了方便实验,关闭防火墙和内核安全机制,并安装LVS管理程序

[root@lvs ~]# systemctl stop firewalld
[root@lvs ~]# setenforce 0
[root@lvs ~]# yum -y install ipvsadm

使用ipvsadm命令来创建集群服务负责将到达192.168.10.172:80的请求根据设定的调度策略分发到后端服务器。

然后可以使用ipvsadm -ln来查看现有的调度策略

  • -g:gateway,指定为DR模式
[root@lvs ~]# ipvsadm -A -t 192.168.10.172:80 -s wrr[root@lvs ~]# ipvsadm -a -t 192.168.10.172:80 -r 192.168.10.102 -g -w 1
[root@lvs ~]# ipvsadm -a -t 192.168.10.172:80 -r 192.168.10.103 -g -w 2
[root@lvs ~]# ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags-> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  192.168.10.172:80 wrr-> 192.168.10.102:80            Route   2      0          0         -> 192.168.10.103:80            Route   2      0          0

Web服务器配置

先右键XShell终端的空白处,开启会话同步

注意只开启102和103两个Web服务器的会话同步,其他根据下图关闭

在102(Web服务器①)操作

为了方便实验,关闭防火墙和内核安全机制

[root@web01 ~]# systemctl stop firewalld
[root@web01 ~]# setenforce 0

绑定VIP

后端服务器要通过本地回环来绑定VIP

这里在本机回环接口上创建一个虚拟子接口,把IP设为VIP,实现封装时的需求

[root@web01 ~]# cd /etc/sysconfig/network-scripts/
[root@web01 network-scripts]# cp ifcfg-lo ifcfg-lo:0
[root@web01 network-scripts]# vim ifcfg-lo:0
DEVICE=lo:0
IPADDR=192.168.10.172
NETMASK=255.255.255.255
#NETWORK=127.0.0.0
#BROADCAST=127.255.255.255
ONBOOT=yes
NAME=loopback
255.255.255.255(/32)
  • 代表完全独立的IP,哪怕有一个相同IP和相同掩码也不会冲突
  • 意味着这个IP地址不再代表一个网络或者子网的一部分,而是指定了一个具体的主机,避免与其他设备的IP地址重叠或冲突
  • 32位掩码的IP通常不用于实际的通信,只用于管理,我们这里就只用于封装数据包

保存并退出,重启网络,可以使用ifconfig查看lo:0有没有创建成功

[root@web01 network-scripts]# systemctl restart network
[root@web01 network-scripts]# ifconfiglo:0:inet 192.168.10.172  netmask 255.255.255.255

设置路由条目

如果有请求访问192.16.16.172就路由给lo:0去处理

使用route命令,指定请求的IP,再指定处理的设备为lo:0但此时只是临时生效,关机后就失效了

要永久生效的话,可以在/etc/rc.local文件末尾追加该命令,来实现开机时自动执行该命令

[root@web01 ~]# route add -host 192.168.10.172 dev lo:0
[root@web01 ~]# vim /etc/rc.local
route add -host 192.168.10.172 dev lo:0

设置内核参数

针对上面概念我们提到的ARP请求的问题,需要修改内核参数,来不让VIP参与ARP的请求和应答

在内核配置文件末尾追加下方代码块中的内容,然后使用sysctl -p应用配置参数

[root@web01 ~]# vim /etc/sysctl.conf 
net.ipv4.conf.all.arp_ignore=1
net.ipv4.conf.all.arp_announce=2
net.ipv4.conf.default.arp_ignore=1
net.ipv4.conf.default.arp_announce=2
net.ipv4.conf.lo.arp_ignore=1
net.ipv4.conf.lo.arp_announce=2
[root@web01 ~]# sysctl -p

安装Web服务

还是在102(Web服务器①)操作(会话同步中)

安装Apache网站服务,启动httpd服务

[root@web01 ~]# yum -y install httpd
[root@web01 ~]# systemctl start httpd

关闭全部会话同步

分别添加测试对应的网页内容

在102(Web服务器①)操作(会话同步关闭)

创建网页文件,添加以下内容

[root@web01 ~]# vim /var/www/html/index.html
Test Web 01

在103(Web服务器②)操作

创建网页文件,添加以下内容

[root@web02 ~]# vim /var/www/html/index.html
Test Web 02

测试

在105(外网客户端)操作

因为在设置调度策略时指定了权重值,所以调度器会把每3次请求中的2次分配给102,1次分配给103

[root@client ~]# curl 192.168.10.172
Test Web 01
[root@client ~]# curl 192.168.10.172
Test Web 02
[root@client ~]# curl 192.168.10.172
Test Web 02
[root@client ~]# curl 192.168.10.172
Test Web 01
[root@client ~]# curl 192.168.10.172
Test Web 02
[root@client ~]# curl 192.168.10.172
Test Web 02
模拟故障

如果把102的网站服务关闭了,只留下一个103,然后让客户端再去访问

[root@client ~]# curl 192.168.10.172
Test Web 02
[root@client ~]# curl 192.168.10.172
Test Web 02
[root@client ~]# curl 192.168.10.172
curl: (7) Failed connect to 192.168.10.172:80; 拒绝连接

因为其中一台后端服务器故障了,而调度策略中又指定了分配请求给该服务器,但是该服务器的服务已经关闭

所以LVS的缺点就是:如果只单独使用LVS来实现负载均衡集群,那么假如有后端服务器故障了,需要手动删除调度策略,LVS不会自动更新调度策略,LVS的还需要借助其他技术手段才能实现真正的高可用


NFS共享存储

在104(共享存储服务器)操作

关闭防火墙和内核安全机制,然后安装nfs文件系统所需依赖

[root@nfs ~]# systemctl stop firewalld
[root@nfs ~]# setenforce 0
[root@nfs ~]# yum -y install nfs-utils
[root@nfs ~]# vim /etc/exports/opt/wwwroot 192.168.10.0/24(rw,sync,no_root_squash)
# 保存并退出

创建共享目录,并启动服务

[root@nfs ~]# mkdir /opt/wwwroot
[root@nfs ~]# systemctl start nfs
[root@nfs ~]# systemctl start rpcbind
挂载共享目录

在102(Web服务器①)操作

安装nfs文件系统所需依赖,使用mount命令指定文件系统类型和挂载位置,再指定挂载点

最后使用df命令查看是否挂载成功

[root@web01 ~]# yum -y install nfs-utils
[root@web01 ~]# mount -t nfs 192.168.10.104:/opt/wwwroot /var/www/html/
[root@web01 ~]# df
文件系统                        1K-块    已用      可用   已用% 挂载点192.168.10.104:/opt/wwwroot 204368640 1901824 202466816    1% /var/www/html

在103(Web服务器②)操作

步骤同上

[root@web02 ~]# yum -y install nfs-utils
[root@web02 ~]# mount -t nfs 192.168.10.104:/opt/wwwroot /var/www/html/
[root@web02 ~]# df
文件系统                        1K-块    已用      可用   已用% 挂载点192.168.10.104:/opt/wwwroot 204368640 1901824 202466816    1% /var/www/html

因为挂载一个目录到/var/www/html目录后,会覆盖该目录原本的内容,所以这里继续在103的挂载点下创建一个测试的网页文件,添加以下内容

[root@web02 html]# vim index.html
NFS Test
测试

在105(外网客户端)操作

最后在客户端测试,共享存储的功能就实现了

[root@client ~]# curl 192.168.10.172
NFS Test
[root@client ~]# curl 192.168.10.172
NFS Test
[root@client ~]# curl 192.168.10.172
NFS Test

案例完成

相关文章:

LVS-DR模式集群:案例与概念

DR模式(直接路由) 概念 Direct Routing,简称DR模式采用半开放式的网络结构,与TUN模式的结构类似,但内网服务器并不是分散在各地,而是与调度器位于同一个物理网络负载调度器与内网服务器通过本地网络连接&a…...

拓扑排序:Kahn算法与DFS算法

引言 拓扑排序是有向无环图(DAG)中的一种线性排序,使得对于图中的每一条有向边 ( u \rightarrow v ),顶点 ( u ) 在排序中出现在顶点 ( v ) 之前。本文将详细介绍两种实现拓扑排序的算法:Kahn算法和基于深度优先搜索&…...

图像处理 -- Sobel滤波器的实现原理与使用案例

Sobel滤波器 概述 Sobel滤波器是一种边缘检测方法,用于图像处理和计算机视觉领域。它通过计算图像灰度值的梯度来检测边缘。Sobel滤波器结合了高斯平滑和微分操作,以减少噪声并增强边缘检测效果。 实现原理 Sobel滤波器通过使用两个3x3卷积核&#x…...

机器学习 第10章-降维与度量学习

机器学习 第10章-降维与度量学习 10.1 k近邻学习 k近邻(k-Nearest Neighbor,简称kNN)学习是一种常用的监督学习方法其工作机制非常简单:给定测试样本,基于某种距离度量找出训练集中与其最靠近的k个训练样本,然后基于这k个“邻居”的信息来进行预测。通…...

linux驱动:(7)物理地址到虚拟地址映射

单片机、裸机、linux操控硬件方法 在单片机和裸机中操作硬件是通过指针来对寄存器赋值来进行操控 但对于linux中不能这样,不能直接对物理地址直接修改,因为linux使能了mmu,所以不能直接菜操作物理地址 如果要操作硬件,需要先把…...

浏览器用户文件夹详解 - Preferences(十)

1.Preferences简介 1.1 什么是Preferences文件? Preferences文件是Chromium浏览器中用于存储用户个性化设置和配置的一个重要文件。每当用户在浏览器中更改设置或安装扩展程序时,这些信息都会被记录在Preferences文件中。通过这些记录,浏览…...

Robot Operating System——电池电量通知

大纲 应用场景定义字段解释 案例 sensor_msgs::msg::BatteryState 是 ROS 2 中定义的消息类型,用于表示电池状态。它包含了电池电量、电压、电流、温度等信息。 应用场景 机器人 电池监控:在移动机器人中,电池是主要的电源。BatteryState 消…...

二进制安装docker

目录 一、准备 Docker CE 二进制包 二、解压.tgz包 三、复制二进制文件到/usr/bin/目录 四、创建用户组 五、配置相关服务配置文件 六、拷贝配置文件到指定目录 七、启动 dockerd 服务进程 八、shell脚本一键安装 一、准备 Docker CE 二进制包 https://download.docker…...

@SpringBootConfiguration重复加载报错

Junit单元测试Test启动报错,SpringBootConfiguration注解重复问题排查: SpringBootApplication 注解的 exclude 属性用于排除特定的自动配置类,而不是用于排除主配置类本身。因此,不能通过 exclude 属性来排除主配置类的加载。 …...

【SpringBoot】数据验证之分组校验

分组校验 在不同情况下,可能对JavaBean对象的数据校验规则有所不同,有时需要根据数据状态对JavaBean中的某些属性字段进行单独验证。这时就可以使用分组校验功能,即根据状态启用一组约束。 Hibernate Validator的注解提供了groups参数&#…...

MySQL Galera Cluster 部署与介绍

目录 主要特点 组件 一. 环境准备 二. 配置 1. 配置 galera1 主机的my.cnf的文件 2. 配置 galera2 主机的my.cnf的文件 3. 配置 galera3 主机的my.cnf的文件 4. 在给galera1 主机的my.cnf的文件增加节点 5. 写入数据验证同步 6. 配置 galera4 主机的my.cnf的文件 M…...

RuoYi-Vue-Plus (XXL-JOB任务调度中心二:配置管理与定时任务编写、执行策略、命令行任务、邮件报警等等

一、后端xxl job的配置属性介绍 enabled : 是否开启执行器,如果为false,调度中心就调用不了后端定时任务admin-addresses:调度中心的地址,多个则可以逗号拼接: url1,url2,url3access-token: 执行器通讯TOKEN ,必须和x…...

【docker】虚拟化与docker基础

一、虚拟化 1.虚拟化概述 什么是虚拟化? 虚拟化:将应用程序和系统内核资源进行解耦,以操作系统级别进行隔离,目的是提高资源利用率 2、虚拟化的功能 将虚拟化的性能优化趋近于物理资源的性能,主要用于提高资源利用…...

Vue3安装ffmpeg做视频截取报错

通过 yarn 安装 ffmpeg 时报错。 即,执行以下指令时报错: yarn add ffmpeg/ffmpeg^0.10.0 yarn add ffmpeg/core^0.10.0错误信息: node_modules\pngquant-bin: Command failed. Error: pngquant failed to build, make sure that libpng-d…...

如何在 Java 中实现自定义的排序算法?

在Java中实现自定义排序算法的步骤如下: 创建一个类,实现Java的Comparator接口,该接口包含一个compare方法,用于比较两个对象的大小。在compare方法中,根据自定义的排序规则,比较两个对象的大小并返回-1、…...

【Homebrew】brew 命令

Brew(也称为Homebrew)是Mac OS上的一款包管理器,它允许用户通过简单的命令行界面来安装、更新、卸载和管理软件包。以下是一些常用的Brew命令及其功能说明: 安装与卸载 安装Brew 命令(适用于大多数用户,可…...

【https】无法安装OpenSSL时如何在局域网开通https服务

【背景】 做Stream传输服务,需要用到fetch方法,所以自然也需要https服务。 公司的开发机由于某些管理上的原因无法直接安装openssl for win的安装包。 【分析】 没有命令行工具,就试试看万能的python包吧,直接安装cryptography包。 pip install cryptography【方法】 …...

OpenGL实现3D游戏编程【连载1】——初探3D世界

1、前言 在我学习C的过程中,研究了一下OpenGL编程,打开了3D世界的编程世界,3D世界的效果还是相当不错。而且OpenGL能够支持跨平台兼容,是不错的学习方向,于是就自己学习了网上的很多教程,并将所有学到的知…...

工程化实践:工程配置化设计

文内项目 Github:XIAOJUSURVEY 配置化是很灵活且很常见的使用,那XIAOJUSURVEY里有哪些地方应用到了呢? 基础模板​ 问卷模板​ 在创建问卷时,我们提供了多种问卷类型选择,例如普通问卷、投票、报名、NPS等。 为了实…...

浏览器事件循环详解

1. 浏览器的进程模型 1.1. 何为进程? 程序运行需要有它自己的专属内存空间,可以把这块内存空间简单的理解为进程。 每个应用至少有一个进程,进程之间相互独立,即使要通信,也需要双方同意。 1.2. 何为线程&#xff1f…...

Linux:线程管理(线程创建、线程退出、线程回收、线程分离、其它线程函数)

线程管理 (1)What(什么是线程管理) 对程序中线程的创建、调度、同步、退出、回收等操作进行有效的控制和协调 (2)Why(为什么要管理线程) 充分利用系统资源,提高程序的并发的性能和稳定性。但如果管理不当,…...

【JVM】常见面试题

🥰🥰🥰来都来了,不妨点个关注叭! 👉博客主页:欢迎各位大佬!👈 文章目录 1. JVM 中的内存区域划分2. JVM 的类加载机制2.1 加载(Loading)✨双亲委派模型2.2 验证(Verification)2.3 准…...

0805作业+梳理

一、作业&#xff1a; 代码&#xff1a; create.c #include<myhead.h> int main(int argc, const char *argv[]) {//创建一个有名管道文件if(mkfifo("./linux",0664)-1){perror("mkfifo linux error");return -1;}getchar();system("rm linux…...

Java高并发编程详解教程(对高并发更深一层的领悟和体会 电子版)

前言 第一部分主要阐述Thread的基础知识&#xff0c;详细介绍线程的API使用、线程安全、线程间数据通信以及如何保护共享资源等内容&#xff0c;它是深入学习多线程内容的基础。 在第二部分中之所以引人 ClassLoader&#xff0c;是因为 ClassLoader 与线程不无关系&#xff0…...

字符串中的第一个唯一字符

给定一个字符串 s &#xff0c;找到 它的第一个不重复的字符&#xff0c;并返回它的索引 。如果不存在&#xff0c;则返回 -1 。 s 只包含小写字母 示例 1&#xff1a; 输入: s "leetcode" 输出: 0示例 2: 输入: s "loveleetcode" 输出: 2示例 3: 输…...

leetcode数论(​3044. 出现频率最高的质数)

前言 经过前期的基础训练以及部分实战练习&#xff0c;粗略掌握了各种题型的解题思路。现阶段开始专项练习。 描述 给你一个大小为 m x n 、下标从 0 开始的二维矩阵 mat 。在每个单元格&#xff0c;你可以按以下方式生成数字&#xff1a; 最多有 8 条路径可以选择&#xff1…...

70.加载功能菜单功能设计

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a;易道云信息技术研究院 上一个内容&#xff1a;69.搭建分析工具界面 以 69.搭建分析工具界面 它的代码为基础进行修改 效果图&#xf…...

在线Banner设计工具大比拼:谁更胜一筹

在数字营销的时代&#xff0c;一个吸引眼球的 Banner 广告是吸引潜在客户、提高品牌知名度的关键。为了帮助营销人员和设计师快速创建专业的 Banner 广告&#xff0c;市面上出现了多种易于使用的 Banner 设计工具。本文将介绍几个受欢迎的 Banner 设计工具&#xff0c;包括即时…...

C++ STL copy, move 用法

一&#xff1a;功能 正向&#xff08;从前向后的顺序&#xff09;拷贝/移动操作&#xff0c;将一个容器元素拷贝/移动到另一容器中。 二&#xff1a;用法 #include <iostream> #include <vector> #include <algorithm>int main() {std::vector<std::str…...

MoonBit 周报 Vol.52:增加类型别名的支持、错误类型声明方式说明、MoonBit AI 支持生成文档等!

weekly 2024-08-05 MoonBit更新 JSON字面量支持array spread。 let xs: Array[json.JsonValue] [1, 2, 3, 4] let _: json.JsonValue [1, ..xs]增加了类型别名的支持&#xff0c;主要是为了渐进式代码重构和迁移&#xff0c;而不是某种给类型简短名字的机制。例如&#xf…...