全国职业技能大赛云计算赛项---Linux系统调优案例

全国职业技能大赛云计算赛项---Linux系统调优案例

    • Linux系统调优案例:
    • OpenStack平台调度策略优化:
    • OpenStack平台镜像优化:
    • OpenStack平台I/O优化:
    • OpenStack 平台内存优化:
    • Linux 系统调优-防止SYN 攻击:

Linux系统调优案例:

1.Linux系统句柄介绍
文件句柄,会随着进程数增加而增加。其实Linux是有文件句柄限制的,而且Linux默认一般都是1024。在生产环境中很容易到达这个值,因此这里就会成为系统的瓶颈。
在Linux系统的生产环境中,会经常遇到“too many open files”的报错。这个报错顾名思义是打开过多文件数。不过这里的files不单是文件的意思,也包括打开的通讯链接(比如socket),正在监听的端口等等,所以有时候也可以叫做句柄(handle),这个错误通常也可以叫做句柄数超出系统限制。
在出现“too many open files”报错的时候,大多数情况是由于程序没有正常关闭一些资源引起的,所以出现这种情况,这个时候需要检查I/O读写,socket通讯等是否正常关闭等。当然也可以通过修改参数,将系统的文件句柄限制提高,来缓解这一压力。

2.Linux系统句柄优化
1.规划节点

IP 主机名节点
192.168.200.21 localhost实验节点

2.基础准备
登录云平台,进入实验自动分配一台CentOS 7.9云主机。使用云主机作为本次案例的实验节点。
(1)查看当前的句柄数
查看当前系统默认的文件句柄数量,所以优化句柄数量限制是很有必要的。命令如下:

[root@localhost ~]# ulimit -n
1024

可以看到系统默认限制是1024。系统默认的1024远远不够,会导致系统报“too many open files”的错误。

(2)修改句柄数.
修改Linux系统的句柄数限制有两种方法,一种是使用ulimit命令临时生效,另外一种是修改配置文件,永久生效。此处使用修改配置文件的方式。
注意:如果使用命令临时生效句柄限制,root用户可以调大或者调小句柄的限制,而非root用户一旦设定了值,就只能调小这个限制,不能调大,不然会报“bash: ulimit: open files: cannot modify limit: Operation not permitted”的错误。

修改配置文件调整句柄限制为65535,命令如下:

[root@localhost ~]# echo “* soft nofile 65535” >>/etc/security/limits.conf
[root@localhost ~]# echo “* hard nofile65535” >> /etc/security/limits.conf

添加配置的解释如下:
● *:代表所有用户。
● soft:超过文件句柄数时,仅提示。
● hard:超过文件句柄数时,直接限制。
修改完之后,不需要重启系统即会生效,但是需要重新登录。退出重新登录该云主机,查看当前的句柄限制,命令如下:

[root@localhost ~]# logout
Connection closed.
Last login: Tue Feb 801:58:31 2022 from 192.168.0.70
[root@localhost ~]# ulimit -n
65535

可以看到当前的限制为65535。

OpenStack平台调度策略优化:

1.规划节点

IP 主机名节点
192.168.200.11 controller控制节点

2.基础准备
根据云平台分配的主机All in one作为实验节点,该案例只研究云平台在大规模创建云主机遇到特定报错时的解决方法。
案例实施

1.OpenStack平台报错分析
在OpenStack平台经历大并发的时候,比如同一个平台,大量的用户同时创建云主机(单个用户创建大量云主机不会触发此种现象),会达到云平台的性能瓶颈,导致创建云主机报错。
大量用户同时创建云主机,会对云平台的两个服务造成性能瓶颈,一个是RabbitMQ,当RabbitMQ达到瓶颈时,会报如下错误:

ERROR oslo.messaging._drivers.impl_rabbit
[req-eb79ea09-247e-49e0-960b-0896ef978661 - - - - -]
[303415c0-e494-4ea2-8158-d66d4165600d] AMQP server on controller:5672
is unreachable: timed out. Trying again in 10 seconds.: timeout: timed
out

另一个就是DHCP。本案例重点讨论DHCP报错的情况,不考虑RabbitMQ的性能瓶颈。DHCP报错信息如下:

WARNING nova.compute.manager [req-8d9240cd-6a47-4979-a289-bdd58d399f0a
891c061e4aea4af8909a4affe0c24f92 c509a52800de4902845460fcc5318f3f -
8d899afee33641e0a094f85fbeb9b2c6 8d899afee33641e0a094f85fbeb9b2c6]
[instance: 374aa944-6cd7-4dbf-a741-5bd44623919d] Received unexpected
event network-vif-plugged-b803941a-c3ae-45d7-b962-13ba1ff00a31 for
instance with vm_state active and task_state None.

在这种情况下,因为大量的创建云主机,导致获取IP地址超时,然后就发生了如上的报错。

注意:这个报错还和计算节点的性能有关,大量创建云主机的时候,计算节点如果没有创建过该镜像的云主机,会先从控制节点复制镜像到计算节点,这也会导致速度变慢。而且在创建大量云主机的时候,对计算节点的硬盘也是一个考验,如果硬盘性能差的话,也会导致创建速度慢,大量排队,超时等现象。

2.解决策略
在解决问题之前,首先了解创建云主机的过程,在创建虚机过程中,Nova-compute会调用wait_for_instance_event函数(nova/compute/manage.py)进行network-vif-plugged的事件等待。
在Nova-compute配置文件中有两个与该事件相关的参数- vif_plugging_timeout、vif_plugging_if_fatal,前者是等待事件的最大时间,后者是处理超时异常的方式。若在规定时间内,Nova-compute接受到了事件响应,那么虚机可正常创建,那么当超时现象发生时,Nova-compute会根据vif_plugging_is_fatal的配置采取两种处理方式。

若超时发生,并且配置文件中vif_plugging_is_fatal为True,Nova首先执行guest.poweroff,停止Qemu进程;然后执行cleanup函数,先清除网络资源,使用函数_unplug_vifs,删除plug_vifs函数创建的ovs port,ovs agent检测到了删除端口的事件然后通知Neutron-server删除neutron db中的port信息,最后抛VirtualInterfaceCreateException。

如果vif_plugging_is_fatal为False,即便发生eventlet.timeout.Timeout异常,创建过程也会继续。然后等虚拟机创建成功后,依然可以拿到IP地址。
通过上述虚拟机创建的过程,对于上述云平台发生的错误,就有了解决的思路,通过修改/etc/nova/nova.conf配置文件,将vif_plugging_is_fatal参数由true改为false,命令如下:
修改/etc/nova/nova.conf配置文件:

[root@controller ~]# vi /etc/nova/nova.conf

找到如下这行:

#vif_plugging_is_fatal=true

将该行的注释去掉,并将true改为false,修改完之后如下:

vif_plugging_is_fatal=false

保存退出nova.conf,最后重启Nova服务,也可以重启所有服务,命令如下:

[root@controller ~]# openstack-service restart

等待重启完毕即可。通过该参数的修改,可解决在大并发量创建虚拟机时,因排队超时导致虚拟机获取不到IP地址的报错。

OpenStack平台镜像优化:

1.OpenStack平台制作镜像
在OpenStack平台的使用过程中,镜像是一个不可或缺的组件与服务,一般来说,使用最多的是基础镜像,比如CentOS7.5;CentOS7.6;CentOS7.9等,获取这些基础镜像的方式也很简单,可以通过官网直接下载。
当用户想使用自定义镜像的时候,可以使用OpenStack平台中打快照的方式,去制作镜像,比如想制作一个带有数据库服务的镜像(具体操作不再演示)。
2.OpenStack平台镜像优化
1.规划节点

IP 主机名节点
192.168.200.11 controller控制节点

2.基础准备
使用云平台分配的All in one作为实验节点,本案例只讲述如何优化通过打快照方式制作的镜像。
案例实施

1.OpenStack平台制作镜像
在OpenStack平台的使用过程中,镜像是一个不可或缺的组件与服务,一般来说,使用最多的是基础镜像,比如CentOS7.5、CentOS7.6、CentOS7.9等,获取这些基础镜像的方式也很简单,可以通过官网直接下载。
当用户想使用自定义镜像的时候,可以使用OpenStack平台中打快照的方式,去制作镜像,比如想制作一个带有数据库服务的镜像,可以按照如下步骤操作:(具体操作不再演示)
(1)启动一个基础的CentOS镜像;
(2)连接虚拟机,配置Yum源;
(3)安装数据库服务;
(4)初始化数据库;
(5)设置开机自启;
(6)在OpenStack平台中将该虚拟机实例打成快照;
(7)在控制节点的镜像和快照存放目录/var/lib/glance/images目录下找到这个镜像文件,改名成mysql.qcow2;
通过上述的方法打快照制作镜像,可以获得一个mysql.qcow2的镜像文件,使用该文件上传至其他云平台中,今后使用该镜像启动的虚拟机,就带有数据库服务了。

2.OpenStack平台镜像优化
在使用打快照方式制作镜像后,镜像的大小会变得非常大,比如一个基础的CentOS镜像大小为400M左右,但是使用打快照方式制作的镜像大小会有1个G左右,具体的大小还要根据安装的东西来实际情况实际分析。

qemu-img命令中提供一个可用于镜像转换与压缩的选项,即qemu-img convert。接下来使用该命令,对已经打快照完成的镜像进行压缩操作。
使用提供的镜像CentOS7.5-compress.qcow2,下载至controller节点的/root目录下,查看镜像的大小,命令如下:

[root@controller ~]# curl -O
http://mirrors.douxuedu.com/competition/CentOS7.5-compress.qcow2
[root@controller ~]# du -sh CentOS7.5-compress.qcow2
892M CentOS7.5-compress.qcow2

可以看到当前的镜像大小为892M,接下来使用命令,对镜像进行压缩,命令如下:

[root@controller ~]# qemu-img convert -c -O qcow2 CentOS7.5-compress.qcow2 CentOS7.5-compress2.qcow2

该命令参数的解释如下:
● -c:压缩。
● -O qcow2:输出格式为 qcow2。
● CentOS7.5-compress.qcow2:被压缩的文件。
● CentOS7.5-compress2.qcow2:压缩完成后文件。
等待一小段时间后,压缩完成,查看当前目录下CentOS7.5-compress2.qcow2镜像文件的大小,命令如下:

[root@controller ~]# du -sh CentOS7.5-compress2.qcow2
405M CentOS7.5-compress2.qcow2

可以看到镜像大概被压缩到了一半的大小。使用qemu-img convert命令可以压缩QCW2镜像,在日常的工作中,经常会用到此命令进行镜像压缩。

OpenStack平台I/O优化:

为什么需要IO调度呢?在最开始的时候,Linux存储在磁盘上。磁盘盘片高速旋转,通过磁臂的移动读取数据。磁臂的移动是物理上的机械上的移动,它无法瞬移,这速度是很慢的。如果我们读取的数据位置很随机,一会在A地点,一会在隔着老远的B地点,移动的时间就全做了无用功,这也就是我们说的随机读写性能慢的原因。如果 读取的数据地址是连续的,即使不是连续的也是地址接近的,那么移动磁臂的时间损耗就少了。在最开始,IO调度的作用就是为了合并相近的IO请求,减少磁臂的移动损耗。

1.单队列I/O调度介绍
登录物理OpenStack平台的Controller节点,查看I/O调度策略,命令如下:
此区域已隐藏一部分内容,点击右侧按钮可展开…
可以看到,物理节点默认使用的是deadline算法。常用的单队列算法就是noop、deadline和cfq,关于这三种调度算法的详细解释如下:
(1)noop
noop只会对请求做一些简单的排序,其本质就是一个FIFO的队列,只会简单地合并临近的I/O请求后,本质还是按先来先处理的原则提交给磁盘。
根据它的原理,我们可以发现它倾向于饿死读利于写,为什么呢?异步写是把数据直接放到page cache的,也就意味着可以通过page cache缓存大量的写数据,再一次性往下提交I/O请求。而读呢?读一般是同步的,也就意味着必须在读完一笔后再读下一笔,两次读之间是可能被写请求插足的。
(2)cfq
CFQ全称Completely Fair Scheduler,中文名称完全公平调度器,它是现在许多Linux发行版的默认调度器,CFQ是内核默认选择的I/O调度器。它将由进程提交的同步请求放到多个进程队列中,然后为每个队列分配时间片以访问磁盘。对于通用的服务器是最好的选择,CFQ均匀地分布对I/O带宽的访问。CFQ为每个进程和线程,单独创建一个队列来管理该进程所产生的请求,以此来保证每个进程都能被很好的分配到I/O带宽,I/O调度器每次执行一个进程的4次请求。该算法的特点是按照I/O请求的地址进行排序,而不是按照先来后到的顺序来进行响应。简单来说就是给所有同步进程分配时间片,然后才排队访问磁盘。
(3)deadline
deadline确保请求在一个用户可配置的时间内得到响应,避免请求饿死。其分别为读I/O和写I/O提供不同的FIFO队列,读FIFO队列的最大等待时间是500ms,写FIFO队列的最大等待时间是5s。deadline会把提交时间相近的请求放在一批。在同一批中,请求会被排序。当一批请求达到了大小上限或着定时器超时,这批请求就会提交到设备队列上去。
总体来讲,deadline算法对request进行了优先权控制调度,主要表现在如下几个方面:
读写请求分离,读请求具有高优先调度权,除非写请求即将被饿死的时候,才会去调度处理写请求。这种处理可以保证读请求的延迟时间最小化。
对请求的顺序批量处理。对那些地址临近的顺序化请求,deadline给予了高优先级处理权。例如一个写请求得到调度后,其临近的request会在紧接着的调度过程中被处理掉。这种顺序批量处理的方法可以最大程度的减少磁盘抖动。
保证每个请求的延迟时间。每个请求都赋予了一个最大延迟时间,如果达到延迟时间的上限,那么这个请求就会被提前处理掉,此时,会破坏磁盘访问的顺序化特征,回影响性能,但是,保证了每个请求的最大延迟时间。
对于这三种调度算法的总结如下:
● noop
对于闪存设备和嵌入式系统是最好的选择。对于固态硬盘来说使用noop是最好的,deadline次之,而CFQ效率最低。
● cfq
为所有进程分配等量的带宽,适用于有大量进程的多用户系统,CFQ是一种比较通用的调度算法,它是一种以进程为出发点考虑的调度算法,保证大家尽量公平,为所有进程分配等量的带宽,适合于桌面多任务及多媒体应用。
● deadline
适用于大多数环境,特别是写入较多的文件服务器,从原理上看,DeadLine是一种以提高机械硬盘吞吐量为思考出发点的调度算法,尽量保证在有I/O请求达到最终期限的时候进行调度,非常适合业务比较单一并且I/O压力比较重的业务,比如Web服务器,数据库应用等。
2.多队列I/O调度介绍
现在有多种multi-queue(多队列)调度器,分别为bfq,none,kyber和mq-deadline。下面对常用调度器的进行介绍:
(1)mq-deadline
mq-deadline调度器跟单队列的deadline调度器发挥的功能很相似。它有个insert_request()函数,不会使用多个staging队列,而是把请求放到两个全局的基于时间的队列中,一个放读请求,一个放写请求,先尝试把该新请求与已经存在的请求合并,如果合并不了,则把这个新请求放到队列尾部。dispatch_request()函数会从这些队列中返回第一个请求:基于时间的队列,基于请求批大小,以及避免写饥饿的队列。
(2)none
多队列无操作I/O调度程序。不对请求进行重新排序,最小的开销。NVME等快速随机I/O设备的理想选择。
3.I/O调度策略修改
1.规划节点

IP 主机名节点
192.168.200.11 controller控制节点

2.基础准备
使用云平台分配的All in one作为实验节点。
案例实施
I/O调度策略修改
调度策略的修改是比较简单的,首先查看当前使用的调度算法,命令如下:

[root@controller ~]# cat /sys/block/vda/queue/scheduler [none]
mq-deadline kyber

可以看到当前的I/O调度算法none,修改算法为mq-deadline,命令如下:

[root@controller ~]# echo mq-deadline > /sys/block/vda/queue/scheduler

修改完之后,查看当前使用的算法,命令如下:

[root@controller ~]# cat /sys/block/vda/queue/scheduler
[mq-deadline] kyber none

可以看到当前的I/O调度算法为mq-deadline模式。
以上就是I/O策略的优化,无论是单队列还是多队列,都可以使用echo命令去修改当前的I/O策略。选择何种策略,也需要根据当前使用的硬盘与应用场景来决定,不能盲目修改。

OpenStack 平台内存优化:

搭建完 OpenStack 平台后,关闭系统的内存共享,打开透明大页。

[root@controller ~]# find / -name defrag
/sys/kernel/mm/transparent_hugepage/defrag
/sys/kernel/mm/transparent_hugepage/khugepaged/defrag
[root@controller~]# echo never > /sys/kernel/mm/transparent_hugepage/defrag
[root@controller ~]# cat /sys/kernel/mm/transparent_hugepage/defrag
always madvise [never]

Linux 系统调优-防止SYN 攻击:

修改 controller 节点的相关配置文件,开启 SYN cookie,防止 SYN 洪水攻击。

[root@container ~]# vim /etc/sysctl.conf
#添加以下参数
net.ipv4.tcp_max_syn_backlog=2048
net.ipv4.tcp_syncookies=1
net.ipv4.tcp_syn_retries = 0
[root@container ~]# sysctl -p
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_syncookies = 1
sysctl: setting key “net.ipv4.tcp_syn_retries”: Invalid argument
net.ipv4.tcp_syn_retries = 0

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

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

相关文章

MySQL笔记 合并查询 外连接 约束

-- 合并查询 union all以及union -- union all就是将两个查询结果合并,不会去重 select ename,sal,job from emp where sal>2500; -- 5条记录 select ename,sal,job from emp where job MANAGER -- 3条记录select ename,sal,job from emp where sal>2500 un…

JUC——并发编程—第二部分

集合类不安全 list不安全 //报错 java.util.ConcurrentModificationException public class ListTest {public static void main(String[] args) {List<String> list new CopyOnWriteArrayList<>();//并发下Arrayist边读边写会不安全的/*** 解决方案&#xff1a…

iPhone苹果手机复制粘贴内容提示弹窗如何取消关闭提醒?

经常使用草柴APP查询淘宝、天猫、京东商品优惠券拿购物返利的iPhone苹果手机用户&#xff0c;复制商品链接后打开草柴APP粘贴商品链接查券时总是弹窗提示粘贴内容&#xff0c;为此很多苹果iPhone手机用户联系客服询问如何关闭iPhone苹果手机复制粘贴内容弹窗提醒功能的方法如下…

Java-API简析_java.util.Objects类(基于 Latest JDK)(浅析源码)

【版权声明】未经博主同意&#xff0c;谢绝转载&#xff01;&#xff08;请尊重原创&#xff0c;博主保留追究权&#xff09; https://blog.csdn.net/m0_69908381/article/details/133463511 出自【进步*于辰的博客】 因为我发现目前&#xff0c;我对Java-API的学习意识比较薄弱…

Linux Ubuntu配置Git的方法

本文介绍在Linux操作系统的Ubuntu版本中&#xff0c;配置分布式开源版本控制系统Git&#xff0c;随后基于Git克隆GitHub中项目的代码的详细方法。 在之前的文章分布式版本控制系统Git的下载、安装与使用其复制GitHub项目代码的方法&#xff08;https://blog.csdn.net/zhebushib…

【前段基础入门之】=>你不知道的 CSS 选择器的进阶使用!

导语&#xff1a; 在上一章节中&#xff0c;我们了解了 CSS 的一些基本语法概念&#xff0c;那么在这一章节中我们就带来 CSS 选择器知识的分享&#xff0c;选择器这一章的知识点有一点多&#xff0c;不过我们只要认真去理解&#xff0c;学习它也是没什么问题的&#xff0c;还有…

【模型压缩】Distiller学习-初认识

Distiller学习-初认识 简介 Intel AILab的神经网络压缩框架&#xff0c;建立在Pytorch基础上 安装 压缩方法 权重正则化方法权重剪枝方法训练后量化方法训练时量化方法条件计算低质分解方法知识蒸馏方法 总体目录 核心代码实现 所有案例的配置文件 举例 初始化网络评价网络…

SpringMVC处理请求流程

一、前言 SpringMVC是一个基于Java的轻量级Web框架&#xff0c;它使用Model-View-Controller&#xff08;MVC&#xff09;设计模式来处理Web请求。 二、请求实现 1、用户发送请求&#xff1a;用户通过浏览器或其他客户端工具向服务器发送一个HTTP请求&#xff0c;请求中包含…

hadoop.ipc:Client

org.apache.hadoop.ipc:Client []- Failed to connect towgqccbsun07/172.29.100.147:8032:server:retries get failed due to exceeded maximum allowed retries number:参考YARN 切换ResourceManager&#xff08;Failed to connect to server:8032 retries get failed due to…

基于Vue和Element UI实现前后端分离和交互

目录 前言 一、Element UI简介 1.Element UI是什么 2.Element UI的特点 二、项目搭建 1.创建一个SPA项目 2.安装 Element-UI 3.导入组件 4.创建登陆注册界面 登录组件---Login.vue 注册组件---Register.vue 定义组件与路由的对应关系 效果演示&#xff1a; 三、前…

1.4.C++项目:仿muduo库实现并发服务器之buffer模块的设计

项目完整版在&#xff1a; 一、buffer模块&#xff1a; 缓冲区模块 Buffer模块是一个缓冲区模块&#xff0c;用于实现通信中用户态的接收缓冲区和发送缓冲区功能。 二、提供的功能 存储数据&#xff0c;取出数据 三、实现思想 1.实现换出去得有一块内存空间&#xff0c;采…

Redis与分布式-集群搭建

接上文 Redis与分布式-哨兵模式 1. 集群搭建 搭建简单的redis集群&#xff0c;创建6个配置&#xff0c;开启集群模式&#xff0c;将之前配置过的redis删除&#xff0c;重新复制6份 针对主节点redis 1&#xff0c;redis 2&#xff0c;redis 3都是以上修改内容&#xff0c;只是…

string模拟实现

string模拟实现 整体代码 #pragma once #include<assert.h>namespace hqj {class string{public:friend ostream& operator<<(ostream& _cout, const hqj::string& s);friend istream& operator>>(istream& _cin, hqj::string& s)…

十、空闲任务及其钩子函数

1、空闲任务的介绍 (1)一个良好的程序&#xff0c;它的任务都是事件驱动的&#xff1a;平时大部分时间处于阻塞状态。 (2)有可能我们自己创建的所有任务都无法执行&#xff0c;但是调度器必须能找到一个可以运行的任务。所以&#xff0c;我们要提供空闲任务。 (3)在使用vTas…

格拉姆角场GAF将时序数据转换为图像并应用于凯斯西楚大学轴承故障诊断(Python代码,CNN模型)

1.运行效果&#xff1a; 格拉姆角场GAF将时序数据转换为图像并应用于故障诊断&#xff08;Python代码&#xff09;_哔哩哔哩_bilibili 环境库 只要tensorflow版本大于等于2.4.0即可运行 2.GAF的内容 GAF是一种用于时间序列数据可视化和特征提取的技术&#xff0c;通常用于…

计算机网络两位伟人

克劳德艾尔伍德香农 克劳德艾尔伍德香农&#xff08;Claude Elwood Shannon&#xff09;是一位美国数学家、电子工程师和计算机科学家&#xff0c;被誉为“信息论之父”。他于1916年生于密歇根州&#xff0c;于2001年去世。以下是一些关于他的详细介绍&#xff1a; 信息论的奠…

蓝桥等考Python组别八级007

第一部分:选择题 1、Python L8 (15分) 运行下面程序,输出的结果是( )。 i = 2 while i < 5: print(i, end = ) i += 1 2 3 4 5 61 2 3 4 52 3 43 4 5正确答案:C 2、Python L8 (

Linux——补充点(进程切换及页表映射)

目录 补充点1&#xff1a;进程地址空间堆区管理 补充点2&#xff1a;Linux内核进程上下文切换 补充点3&#xff1a;页表映射 补充点4&#xff1a;两级页表 补充点1&#xff1a;进程地址空间堆区管理 Linux内核通过一个被称为进程描述符的task_struct结构体来管理进程&#…

keil调试的时候没问题,下载时候没反应

今天遇到这样一个问题。我下载商家的代码例程后单片机没反应&#xff0c;进入调试的时候一切正常。很奇怪&#xff0c;在网上找了教程问题解决&#xff0c;总结一下。 原因在于程序下载进去后没有按下复位键&#xff0c;导致还是之前的程序。我之前设置的是下载后自动复位运行…

【STL】用一棵红黑树封装map和set

⭐博客主页&#xff1a;️CS semi主页 ⭐欢迎关注&#xff1a;点赞收藏留言 ⭐系列专栏&#xff1a;C进阶 ⭐代码仓库&#xff1a;C进阶 家人们更新不易&#xff0c;你们的点赞和关注对我而言十分重要&#xff0c;友友们麻烦多多点赞&#xff0b;关注&#xff0c;你们的支持是我…