怎么样自己做网站/做销售怎么和客户聊天
参考资料
- https://blog.csdn.net/TZ845195485/article/details/119745735
Redis单线程和多线程问题的背景
Redis里程碑版本迭代
Redis的单线程
-
主要是指Redis的网络IO和键值对读写是由一个线程来完成的,Redis在处理客户端的请求时包括获取(socket读)、解析、执行、内容返回(socket写)等都由一个顺序串行的主线程处理,这就是所谓的“单线程”。这也是Redis对外提供键值存储服务的主要流程。
-
但Redis的其他功能,比如持久化RDB、AOF、异步删除、集群数据同步等等,其实是由额外的线程执行的。
-
Redis命令工作线程是单线程的,但是整个Redis来说是多线程的
Redis为什么选择单线程?
- 基于内存操作:Redis的所有数据都存在内存中,因此所有的运算都是内存级别的,性能比较高;
- 数据结构简单:Rdis的数据结构是专门设计的,而这些简单的数据结构的查找和操作的时间大部分复杂度都是O(1),因此性能比较高
- 多路复用和非阻塞I/O:Redis使用I/O多路复用功能来监听多个socket连接客户端,这样就可以使用一个线程连接来处理多个请求,减少线程切换带来的开销,避免了IO阻塞操作
- 避免上下文功换:因为是单线程模型,因此就避免了不必要的上下文切换和多线程竞争,这就省去了多线程切换带来的时间和性能上的消耗
Redis为什么开始利用多核?
https://redis.io/docs/getting-started/faq/#how-can-redis-use-multiple-cpus-or-cores
It’s not very frequent that CPU becomes your bottleneck with Redis, as usually Redis is either memory or network bound.
As of version 4.0, Redis has started implementing threaded actions. For now this is limited to deleting objects in the background and blocking commands implemented via Redis modules. For subsequent releases, the plan is to make Redis more and more threaded.
使用多核的必要性
-
Redis4.0引入异步删除,在删除大key时,单线程会出现阻塞(类似synchronized锁)
unlink key flushdb async flushall async
-
利用惰性删除避免阻塞。因为Redis是单个主线程处理,而
lazy free
的本质就是把某些cost(主要时间复制度,占用主线程cpu时间片)较高删除操作,从redis主线程剥离让bio子线程来处理,极大地减少主线阻塞时间。从而减少删除导致性能和稳定性问题。
Redis当前的性能瓶颈
-
redis主要的性能瓶颈是内存或者网络IO,而不太可能是cpu
-
虽然有些命令操作可以用后台线程或子进程执行(比如数据删除、快照生成、AOF重写)。但是从网络IO处理到实际的读写命令处理,都是由单个线程完成的。
-
单个主线程处理网络请求的速度跟不上底层网络硬件的速度,为了应对这个问题采用多个IO线程来处理网络请求,提高网络请求处理的并行度,Rdis6/7就是采用的这种方法。
但是,Redis的多IO线程只是用来处理网络请求的,对于读写操作命令Redis仍然使用单线程来处理。这是因为Redis处理请求时,网络处理经常是瓶颈,通过多个IO线程并行处理网络操作,可以提升实例的整体处理性能。而继续使用单线程执行命令操作,就不用为了保证Lua脚本、事务的原子性,额外开发多线程互斥加锁机制,这样一来Redis线程模型实现就简单了
Redis的主线程如何和IO线程协同
既然瓶颈是网络IO,Redis的主线程如何和IO线程协同?
- 服务端和客户端建立Socket连接,并分配处理线程。首先,主线程负责接收建立连接请求。当有客户端请求和实例建立Socket连接时,主线程会创健和客户的连接,并把Socket放入全局等待队列中。紧接看主线程通过轮询方法把Socket连接分配给IO线程
- IO线程读取并解折请求。主线程一旦把Socket分配给IO线程,就会进入阻塞状态,等待IO线程完成客户端请求读取和解析。因为有多个IO线程在并行处理,所似这个过程很快完成
- 主线程执行请求操作。等IO线程解析完请求,主线程以单线程的方式执行这些命令操作。
- IO线程回写Socket和主当主线程清空全局队列。主线程执行完请求操作后,会把需要返回的结果写入缓冲区,然后主线程会阻塞等待IO线程,把这些结果回写到Socket中(多个线程在并发执行),并返回给客户端。等到lO线程回写Socket完毕,主线程会清空全局队列,等待客户端的后续请求。
IO多路复用的理解
linux的5种IO模型的理解
当用户进程调用了select,那么整个进程会被block,而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程。
IO多路复用的解释,即使用一个或一组线程处理多个tcp连接
- IO,指代网络IO,需要进行模态转换的读写操作
- 多路,多个客户端连接(socket)
- 复用,复用一个或多个线程、
一个服务端进程可以同时处理多个socket,IO多路复用模型包括select,poll,epoll
在单个线程通过记录跟踪每一个Sockek(I/O流)的状态来同时管理多个I/O流。一个服务端进程可以同时处理多个套接字描述符。目的是尽量多的提高服务器的吞吐能力。
将用户socket对应的文件描述符(FileDescriptor)注册进epoll,然后epoll监听哪些socket上有消息到达,这样就避免了大量的无用操作。此时的socket应该采用非阻塞模式。这样整个过程只在调用select.、poll、epoll这些调用的时候才会阻塞,收发客户消息是不会阻塞的,整个进程或者线程就被充分利用起来,这就是事件驱动,所谓的reactor模式。
因此IO多路复用+epoll也是Redis速度快的根本保证。redis的多线程即
- 单个工作线程保证线程安全和高性能
- 多个IO线程解决网络IO的问题
在redis6/7中,IO多路复用默认是关闭的,有2个相关的配置
################################ THREADED I/O ################################## Redis is mostly single threaded, however there are certain threaded
# operations such as UNLINK, slow I/O accesses and other things that are
# performed on side threads.
#
# Now it is also possible to handle Redis clients socket reads and writes
# in different I/O threads. Since especially writing is so slow, normally
# Redis users use pipelining in order to speed up the Redis performances per
# core, and spawn multiple instances in order to scale more. Using I/O
# threads it is possible to easily speedup two times Redis without resorting
# to pipelining nor sharding of the instance.
#
# By default threading is disabled, we suggest enabling it only in machines
# that have at least 4 or more cores, leaving at least one spare core.
# Using more than 8 threads is unlikely to help much. We also recommend using
# threaded I/O only if you actually have performance problems, with Redis
# instances being able to use a quite big percentage of CPU time, otherwise
# there is no point in using this feature.
#
# So for instance if you have a four cores boxes, try to use 2 or 3 I/O
# threads, if you have a 8 cores, try to use 6 threads. In order to
# enable I/O threads use the following configuration directive:
#
# io-threads 4
#
# Setting io-threads to 1 will just use the main thread as usual.
# When I/O threads are enabled, we only use threads for writes, that is
# to thread the write(2) syscall and transfer the client buffers to the
# socket. However it is also possible to enable threading of reads and
# protocol parsing using the following configuration directive, by setting
# it to yes:
#
# io-threads-do-reads no
#
# Usually threading reads doesn't help much.
#
# NOTE 1: This configuration directive cannot be changed at runtime via
# CONFIG SET. Also, this feature currently does not work when SSL is
# enabled.
#
# NOTE 2: If you want to test the Redis speedup using redis-benchmark, make
# sure you also run the benchmark itself in threaded mode, using the
# --threads option to match the number of Redis threads, otherwise you'll not
# be able to notice the improvements.
线程数不要超过机器的核心数
深入理解Redis的IO多路复用
Redis利用epoll来实现IO多路复用,将连接信息和事件放到队列中,依次放到文件事件分派器,事件分派器将事件分发给事件处理器。
Rdis是跑在单线程中的,所有的操作都是按照顺序线性执行的,但是由于读写操作等待用户输入或输出都是阻塞的,所以I/O操作在一般情况下往往不能直接返回,这会导致某一文件的I/O阻塞导致整个进程无法对其它客户提供服务,而I/O多路复用就是为了解决这个问题而出现
所谓I/O多路复用机制,就是说通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或写就绪),能够通知程序进行相应的读写操作。这种机制的使用需要select、pol川、epol来配合。多个连接共用一个阻塞对象,应用程序只需要在一个阻塞对象上等待,无需阻塞等待所有连接。当某条连接有新的数据可以处理时,操作系统通知应用程序,线程从阻塞状态返回,开始进行业务处理。
Redis服务采用Reactor的方式来实现文件事件处理器(每一个网络连接其实都对应一个文件描述符
Redis基于Reactor模式开发了网络事件处理器,这个处理器被称为文件事件处理器。它的组成结构为4部分:
- 多个套接字
- IO多路复用程序
- 文件事件分派器
- 事件处理器。
因为文件事件分派器队列的消费是单线程的,所汉Reds才叫单线程模型
解释为什么从bio,nio到io多路复用
在bio场景下,当client1请求并和server建立连接后,server在accept和read处发生阻塞,此时新的client2建立连接的请求无法被server处理(处于阻塞中)
注意:这里的应用程序指代的是server端
如何解决服务器主线程阻塞的问题?
考虑使用子线程来处理新的客户端连接和请求。在连接socket后创建线程来处理read操作
client代码
Socket socket = new Scoket("127.0.0.1",6379);
OutputStream outputStream == socket.getOUtputStream();
// 获取标准输入到msg
outputStream.write(msg.getBytes());
server代码
ServerSocket serverSocket = new ServerSocket(6379);
while(true){Socket socket = serverSocket.accept(); // 阻塞等待连接new Thread(() -> {try{InputStream inputStream = socket.getInputStream();// 从input中获取输入,阻塞在读请求socket.close();}},Thread.currentThread().getName()).start();
}
如何解决多线程资源浪费的问题
多线程模型要求每到来一个请求,就切换到内核态创建对应的的进程。新的进程和上下文切换都会产生性能的损耗
- 池化技术,但是实际的线程数量未知
- NIO,使read方法不阻塞
NIO的特点是使用轮询替代阻塞
在客户端,如果kernal中的数据没有准备好,则会返回error
在NIO中一切都是非阻塞的
- accept方法非阻塞,如果没有客户端连接则返回无连接标识
- read方法非阻塞,如果read读不到数据返回空间中标识,有数据则只阻塞read读取数据的时间
- nio中服务端只有一个线程,对socker数组进行遍历
客户端代码和bio下相同
Socket socket = new Scoket("127.0.0.1",6379);
OutputStream outputStream == socket.getOUtputStream();
// 获取标准输入到msg
outputStream.write(msg.getBytes());
服务端代码
- 通过ServerSocketChannel的configureBlocking(false)方法将获得连接设置为非阻塞的。此时若没有连接,accept会返回null
- 通过SocketChannel的configureBlocking(false)方法将从通道中读取数据设置为非阻塞的。若此时通道中没有数据可读,read会返回-1
static ArrayList<SocketChannel> socketList = new ArrayList<>(); // 容纳socket数组
static ByteBuffer byteBuffer = ByteBuffer.allocate(1024); // 输入缓冲ServerSocketChannel serverSocket = new ServerSocketChannel.open();
serverSocket.bind(new InetSocketAddress(127.0.0.1,6379));
serverSocket.configureBlocking(false); // jdk1.4开始兼容阻塞模式,此处设置为非阻塞while(true){for (SocketChannel element : socketList){int read = element.read(byteBuffer); //不会阻塞if(read > 0){byteBuffer.flip();byte[] bytes = new byte[read];byteBuffer.get(byte);byteBuffer.clear();}}SocketChannel socketChannel = serverSocket.accpet(); // 不会阻塞if(socketChannel != null){sockerChannel.configureBlocking(false);socketList.add(socketChannel) // 连接成功}
}
NIO模型存在的问题
- socketlist遍历存在性能瓶颈(空socket仍旧会轮询),cpu不友好
- 对socket状态的判断仍旧需要切换模态(查询socket仍旧是通过read syscall),开销较大、
- 轮询会不断询问内核,占用了大量cpu时间,系统资源利用率较低
如何解决NIO模型cpu不友好的问题?
如果通过linux内核完成上述工作(遍历socket),不需要模态切换,内核本身是非阻塞的。
多路复用就是使用一个信道传输多个信号,多个网络连接使用一个线程,多个socket使用一个通道是在内核和驱动层实现的
IO多路复用模型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aRXsM3LX-1687616915979)(null)]
基于I/O复用模型:多个连接共用一个阻塞对象,应用程序只需要在一个阻塞对象上等待,无需阻塞等待所有连接。当某条连接有新的数据可以处理时,操作系统通知应用程序,线程从阻塞状态返回,开始进行业务处理。
Reactor模式,是指通过一个或多个输入同时传递给服务处理器的服务请求的事件驱动处理模式。服务端程序处理传入多路请求,并将它们同步分派给请求对应的处理线程,Reactor模式也叫Dispatcher模式。即I/O多了复用统一监听事件,收到事件后分发(Dispatch给某进程),是编写高性能网络服务器的必备技术。Reactor模式中有2个关键组成:
- Reactor,Reactor在一个单独的线程中运行,负贵监听和分发事件,分发给适当的处理程序来对IO事件做出反应。它就像公司的电话接线员,它接听来自客户的电话并将线路转移到适当的联系人
- Handlers,处理程序执行I/O事件要完成的实际事件,类似于客户想要与之交谈的公司中的实际办理人。Reactor通过调度适当的处理程序来响应I/O事件,处理程序执行非阻塞操作
IO多路复用的具体实现
select方法
select函数监视的文件描述符分3类,分别是readfds、writefds和exceptfds
,将用户传入的数组拷贝到内核空间
-
调用后select函数会阻塞,直到有描述符就绪(有数据可读、可写、或者有except)或超时(timeout指定等待时间,如果立即返回设为null即可),函数返回
-
当select函数返回后,可以通过遍历fdset,来找到就绪的描述符。
分析select函数的执行流程:
- select是一个阻塞函数,当没有数据时,会一直阻塞在select调用
- 当有数据时会将rset中对应的位置为1
- selecti函数返回,不再阻塞
- 遍历文件描述符数组,判断哪个fd被置位
- 读取数据,然后处理
下面的示例代码
-
实际是将之前java示例的代码从用户态搬到内核态运行
-
将
fd
拷贝到内核态,避免模态切换
sockfd = socket(AF_INET,SOCK_STREAM,0);
memse(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(2000);
addr.sin_addr.s_addr = INADDR_ANY;
bind(sockfd,(struct sockaddr*)&addr, sizeof(addr));
listen (sockfd, 5);
for(i=0;i<5;i+){// 模拟5个客户端连接memset(&client,0,sizeof (client)); addrlen = sizeof(client);fds[i] = accept(sockfd, (struct sockaddr*)&client, &addrlen);if(fds[i]>max)max = fds[i]; //找到一个最大的文件描述符,在下面select中限制范围
}while(1){FD_ZERO(&rset); // 重置rset为0for(i=0;i<5;i++){FD_SET(fds[i],&rset); // &rset是个bitmap.如果5个文件描述符分别是1,2,4,5,7,那么这个bitmap为01101101}puts("round again"); select(max+1,&rset,NULL,NULL,NULL); // select是一个系统调用,它会堵塞直到有数据发送到socket,select会把&rset相应的位置置位,但并不会返回哪个socket有数据for(i=0;i<5;i++){// 用户态只要遍历&rst,看哪一位被置位了,不需要每次调用系统调用来判断了,效率有很大提升,遍历到被置位的文件描述符就进行读取if (FD_ISSET(fds[i],&rset)){memset(buffer, 0, MAXBUF);read(fds[i], buffer, MAXBUF);puts(buffer);}
}
select函数的缺点
- bitmap默认大小为1024(代码实现较早1983年),虽然可以调整但还是有限度的
- rset每次循环都必须重新置位为0,不可重复使用
- 尽管将rset从用户态拷贝到内核态由内核态判断是否有数据,但是还是有拷贝的开销
- 当有数据时select就会返回,但是selecti函数并不知道哪个文件描述符有数据了(仅仅置位)。后面还需要再次对文件描述符数组进行遍历,效率比较低
poll方法
函数原型
int poll(struct pollfd *fds,nfds_t nfds,int timeout);
struct pollfdint fd; //file descriptor short events; // 读或者写事件short revents; // 文件描述符有事件则置1
};
poll的执行流程:
- 将五个fd从用户态拷贝到内核态
- poll为阻塞方法,执行poll方法,如果有数据会将fd对应的revents置为POLLIN
- poll方法返回
- 循环遍历,查找哪个fd被置位为POLLIN了
- 将revents重置为0便于复用
- 对置位的fd进行读取和处理
解决的问题
- 不在使用bitmap,消除了client的大小限制(1024)
- rset不可复用的问题(每次置0)
代码实现
for(1=0;1<5;1++) //模拟5个客户端连接
{memset(&client,0,sizeof (client));addrlen = sizeof(client);pollfds[i].fd = accept(sockfd,(struct sockaddr)&client,&addr);pollfds[i].events = POLLIN; //这5个socket只读事件
}c
sleep(1);
while(1){puts("round again");poll(po11fds,5,50000); // poll中传入pollfds数组,交给内核判断是否有事件发生,如果哪个发生事件则revents置1for(1=0; 1<5; 1++){ //遍历数组,找到哪个pollfd有事件发生if (pollfds[i].revents & POLLIN){pollfds[i].revents=O; // 找到后revents置0memset(buffer,0,MAXBUF);read(pollfds[i].fd,buffer,MAXBUF); //读取数据puts(buffer);}
}
缺点
- 本质上还是select方法
- 拷贝fd到内核态仍旧存在开销
- 仍旧需要遍历socket(O(n)复杂度)
epoll方法
函数原型
// 创建一个epoll的句柄,size表示内核监听的数目。并非最大限制,而是内核初始分配数据结构的建议值
int epoll_create(int size); // 向内核添加,修改或删除要监控的fd
int epoll_ctl(int epfd, // epfd是epoll_create的返回值1nt op, // 表示op操作,用三个宏来表示:添加EPOLL.CTL_ADD,除EPOLL.CTL_DEL,修改EPOLL.CTL_MODint fd, //fd:是需要监听的fd(文件描述符)struct epoll_event *event // 告诉内核要监听什么事
);
struct epoll_event// events可以是以下几个宏的熊合:// EPOLLIN:表示对应的文件描述符可以读(包括对端SOCKET正常关闭);// EPOLLOUT:表示对应的文件描述符可以写;__uint32_t events;epoll_data_t data; // User data variable
}// 类似select调用
int epoll_wait(int epfd,struct epoll event *events,int maxevents, // 最多返回的事件数int timeout
);
具体实现
- socket生命周期只会从用户态到内核态拷贝一次
- 使用event通知级值,每次socket有数据会主动通知内核加入就绪列表,不需要遍历所有socket
struct epoll_event events[5];
int epfd epoll_create(10); // epoll_create在内核开辟一块内存空间,用来存放epolle中fd的数据结构for(i=0;i<5;i+) { //模拟S个客户端连接static struct epoll_event ev; // epoll中fd的数据结构和polI中的差不多,只是没有了reventsmemset(&client,0,sizeof (client));addrlen sizeof(client); ev.data.fd = accept(sockfd,(struct sockaddr&client,&addrlen);ev.events = EPOLLIN;epoll_ctl(epfd,EPOLL_CTL_ADD,ev.data.fd,&ev); // epoll ctl把每-个socket的fd数据结构放到epoll_create创建的内存空间中
}while(1){puts("round again");nfds = epoll_wait(epfd,events,5,1O0O0); // epoll_wait阻塞,只有当epoll_create中创建的内存空间中的fd有事件发生,才会把这些fd放入就绪链表中,返回就绪fd的个数for(i=0;i<nfds;i++){ //遍历就绪链表,读取数据memset(buffer,0,MAXBUF);read(events[i].data.fd, buffer, MAXBUF);puts(buffer);}
}
三个方法的对比
- 不同操作系统选择的方式不同,windows没有epoll默认为select
select | poll | epoll | |
---|---|---|---|
操作方式 | 遍历 | 遍历 | 回调 |
数据结构 | bitmap | 数组 | 红黑树 |
最大连接数 | 1024或2048(x64) | 无限 | 无限 |
最大支持fd数 | 无限 | 65535 | 65535 |
fd跨态拷贝 | 每次select调用都需要拷贝 | 每次poll调用都需要拷贝 | 首次调用epoll_ctl拷贝 |
工作效率 | 线性遍历,O(n) | 线性遍历,O(n) | 事件通知,O(1) |
elasticache7的增强IO
Amazon ElastiCache for Redis 7 新增功能:通过增强型 I/O 多路复用将吞吐量提升高达 72%
使用 ElastiCache for Redis 7 时,将会免费自动提供增强型 I/O 多路复用功能
采用增强型 I/O 后,引擎将专注于处理命令的运行,而非处理网络连接。不再为每个客户端打开一个通道,而是如下图所示,由每个增强型 I/O 线程使用 ElastiCache for Redis 引擎将命令组合在单个通道中
相关文章:

理解redis的多线程和IO多路复用
参考资料 https://blog.csdn.net/TZ845195485/article/details/119745735 Redis单线程和多线程问题的背景 Redis里程碑版本迭代 Redis的单线程 主要是指Redis的网络IO和键值对读写是由一个线程来完成的,Redis在处理客户端的请求时包括获取(socket读&a…...

iOS 开发 | 自定义不规则 label
把我之前发布在简书的博客搬运过来。 目录 场景思路具体实现1. 自定义一个继承自UILabel的IrregularLabel2. 在初始化方法中进行相应初始化和设置3. 在layoutSubviews方法中进行路径的设置 最终效果箭头 label 场景 最近 App 改版,以下是截取的部分 UI 设计图&…...

client-go的Indexer三部曲之三:源码阅读
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 《client-go的Indexer三部曲》全部链接 基本功能性能测试源码阅读 本篇概览 本文是《client-go的Indexer三部曲》系列的终篇,主要任务是阅读和…...

收件地址解析成 省+市+区+详细地址的形式
项目中的源代码在我的GitHub:https://github.com/weitw/address-analyzer 先看效果: 如上图,address数输入的地址,Address对象是解析后的地址。可以支持逆推上一级,且支持地址白话解析。 一、项目介绍 1、解析规则 …...

数据结构与算法基础(青岛大学-王卓)(5)
叮叮咚咚,新一期来袭,我还在吃桃子,吃桃子,吃桃子。。。串和python的字符串差不多,数组和广义表像是python的list 文章目录 串(string) - 字符串概念及术语串的类型定义存储结构(同线性表)串的模式匹配算法…...

微信小程序开发入门学习01-TDesign模板解读
目录 1 使用模板创建小程序2 app.json3 页面布局总结 原来我们使用微信开发者工具,比较困难的是前端框架的选择上,官方也没有提供一套框架供我们使用,最近开发者工具已经提供了一套前端框架,后续我们开发的效率会因为使用模板提高…...

使用 Jetpack Compose 创建自定义的对话框(Dialog)
在 Jetpack Compose 中,对话框(Dialog)是一种常见的用户界面组件,用于展示重要的信息、确认操作或者收集用户输入。本篇博客将带你深入了解 Jetpack Compose 中的对话框,并展示如何创建自定义的对话框,以满…...

c++ auto学习笔记
一、auto的意义 在C11中赋予auto的意义是:在声明变量时,根据初始化表达式自动推断该变量的类型。声明函数时作为函数返回值的占位符(用在函数返回类型后置的情况)。 如 auto i 6; //auto推断为intauto func()->int //函数返…...

【随机种子初始化】一个神经网络模型初始化的大坑
1 问题起因和经过 半年前写了一个模型,取得了不错的效果(简称项目文件1),于是整理了一番代码,保存为了一个新的项目(简称项目文件2)。半年后的今天,我重新训练这个整理过的模型&…...

翻过那座山——Gitlab流水线任务疑难之编译有子模块的项目指南
📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!📢本文作者:由webmote 原创📢作者格言:新的征程,我们面对的不是…...

手机照片删除后如何恢复
在如今移动互联网和智能手机时代,拍摄照片已经成为了人们常见的一种生活方式,尤其是通过手机拍摄照片已经成为了许多人记录生活点滴、分享经验和表达情感等的必备工具。但是,随着手机照片量的激增,意外删除手机中珍贵照片的事件也…...

SpringBoot 线上服务假死,CPU 内存正常,什么情况?
背景 开发小伙伴都知道线上服务挂掉,基本都是因为cpu或者内存不足,出现GC频繁OOM之类的情况。本篇文章区别以上的情况给小伙伴们带来不一样的服务挂掉。 还记得哔哩哔哩713事故中那场诡计多端的0吗? 图片 对就是这个0,和本次事…...

kotlin从入门到精通之内置类型
基本类型 声明变量 val(value的简写)用来声明一个不可变的变量,这种变量在初始赋值之后就再也不能重新赋值,对应Java中的final变量。 var(variable的简写)用来声明一个可变的变量,这种变量在初始…...

实战指南:使用Spring Boot实现消息的发送和接收
当涉及到消息发送和接收的场景时,可以使用Spring Boot和消息中间件RabbitMQ来实现。下面是一个简单的示例代码,展示了如何在Spring Boot应用程序中创建消息发送者和接收者,并发送和接收一条消息。 首先,你需要进行以下准备工作 确…...

常用的数据结构——栈
目录 1、入栈 2、出栈 3、获取栈顶的元素 4、从栈中查找元素 栈是一种常见的数据结构,栈的特点是后进先出,就像我们叠盘子,拿走上面的盘子才能拿到下一个。java中的栈java.util.Stack是通过java.util.Vector实现的,所以底层都…...

C++完成淄博烧烤节管理系统
背景: 这次我们结合今年淄博烧烤做一个餐厅管理系统,具体需求如下,我们选择的是餐饮商家信息管理 问题描述: 淄博烧烤今年大火,“进淄赶烤”是大家最想干的事情,淄博烧烤大火特火的原因,火的…...

我心中的TOP1编程语言
目录 一、评选最佳编程语言时需要考虑哪些标准 (一)易用性 (二)执行效率 (三)语言功能特性 (四)工具生态环境 (五)开发者社区 二、不同编程语言的优点…...

Linux工具之gdb(含移植到arm-linux系统)
文章目录 文件目录结构移植ncurses库移植gdb移植到arm板调试测试 linux主机:ubuntu-18.04 交叉编译器:arm-buildroot-linux-gnueabihf 开发板kernel:Linux 5.4.0-150-generic x86_64 开发板:100ASK_STM32MP157_PRO开发板 arm-…...

DolphinScheduler
参考 Apache DolphinScheduler v1.3.9 使用手册 内置组件 masterserverworkserverzookeepertask queuealertapiui 设计 去中心化设计 通过zk选举 UI功能 队列管理 Yarn调度器的资源队列 用户管理 租户对应的是Linux系统用户,是Worker执行任务使用的用户 用户…...

10大白帽黑客专用的 Linux 操作系统
平时在影视里见到的黑客都是一顿操作猛如虎,到底他们用的都是啥系统呢? 今天给大家分享十个白帽黑客专用的Linux操作系统。 ▍1. Kali Linux Kali Linux是最著名的Linux发行版,用于道德黑客和渗透测试。Kali Linux由Offensive Security开发&…...

Golang每日一练(leetDay0099) 单词规律I\II Word Pattern
目录 290. 单词规律 Word Pattern 🌟 291. 单词规律 II Word Pattern ii 🌟🌟 🌟 每日一练刷题专栏 🌟 Rust每日一练 专栏 Golang每日一练 专栏 Python每日一练 专栏 C/C每日一练 专栏 Java每日一练 专栏 …...

linux_centos7.9/ubuntu20.04_下载镜像及百度网盘分享链接
1、镜像下载站点 网易开源镜像:http://mirrors.163.com/ 搜狐开源镜像:http://mirrors.sohu.com/ 阿里开源镜像:https://developer.aliyun.com/mirror/ 首都在线科技股份有限公司:http://mirrors.yun-idc.com/ 常州贝特康姆软件技…...

Reqable HTTP一站式开发+调试工具(小黄鸟作者另一力作、小黄鸟完美替代品)
本文所有教程及源码、软件仅为技术研究。不涉及计算机信息系统功能的删除、修改、增加、干扰,更不会影响计算机信息系统的正常运行。不得将代码用于非法用途,如侵立删!Reqable HTTP一站式开发+调试工具(小黄鸟作者另一力作、小黄鸟替代品) 环境 win10pixel4Android13概览 …...

Yacc 与 Lex 快速入门
Yacc 与 Lex 快速入门 简介: Lex 和 Yacc 是 UNIX 两个非常重要的、功能强大的工具。事实上, 如果你熟练掌握 Lex 和 Yacc 的话,它们的强大功能使创建 FORTRAN 和 C 的编译器如同儿戏。本文详细的讨论了编写自己的语言和编译器所 用到的这两…...

【开源与项目实战:开源实战】80 | 开源实战二(下):从Unix开源开发学习应对大型复杂项目开发
上两节课,我们分别从代码编写、研发管理的角度,学习了如何应对大型复杂软件开发。在研发管理这一部分,我们又讲到比较重要的几点,它们分别是编码规范、单元测试、持续重构和 Code Review。其中,前三点在专栏的理论部分…...

【单周期CPU】LoongArch | 立即数扩展模块Ext | 32位算术逻辑运算单元(ALU)
前言:本章内容主要是演示在vivado下利用Verilog语言进行单周期简易CPU的设计。一步一步自己实现模型机的设计。本章先介绍单周期简易CPU中基本组合逻辑部件的设计。 💻环境:一台内存4GB以上,装有64位Windows操作系统和Vivado 201…...

Python实现数据结构的基础操作
目录 一、列表(List) 二、字典(Dictionary) 三、集合(Set) 四、链表的实现 五、队列和栈 数据结构是计算机科学中非常重要的概念,它用于存储和组织数据以便有效地进行操作。Python作为一种…...

20230624----重返学习-vue-响应式处理思路-仿源码
day-098-ninety-eight-20230624-vue-响应式处理思路-仿源码 vue vue大体概念 Vue是渐进式框架 所谓渐进式框架,就是把一套全面的框架设计体系,拆分成为多个框架,项目中需要用到那些需求,再导入对应的框架,以此来保证…...

【MongoDB】三、使用Java连接MongoDB
【MongoDB】三、使用Java连接MongoDB 实验目的实验内容练习1、开启Eclipse,创建Java Project项目,命名为Mongo12、添加项目依赖的jar包3、创建类MongoDemo4、连接数据库5、查看集合6、创建集合7、删除集合8、查看文档9、插入文档10、更新文档11、删除文档…...

【C++】通讯录的基本实现,附有源码分享
目录 1、运行环境 2、系统实现功能 2.1菜单功能 2.2退出通讯录功能 2.3添加联系人功能 2.4显示联系人功能 2.5删除联系人功能 2.6查找联系人功能 2.7修改联系人功能 2.8清空联系人功能 2.9动态扩容功能 2.10选择优化功能 2.11文件操作 3、源码分享 1、运行环境 …...