高级java软件工程师面试题库,性能追击,你不看绝对血亏的Volatile全方位解析

主进程收到SIGNUP信号时,会执行如下操作:

  • 重新加载配置,并派生一组新的工作进程,这组新的工作进程立即开始接受连接并处理流量;

  • 指示旧的工作进程正常退出,工作进程停止接收新连接,当前的每个请求处理完成之后,旧的工作进程就会关掉,一旦所有的连接关闭,工作进程就将退出。

性能追击:万字长文30+图揭秘8大主流服务器程序线程模型展示

这种重新加载配置过程可能导致CPU的内存使用量小幅度提升,但是这个性能牺牲是值得的。

3.5、优雅的升级

Nginx的二进制升级过程也实现了不停服的效果。

性能追击:万字长文30+图揭秘8大主流服务器程序线程模型展示

升级过程与政策重新加载配置的方法类型,新的Nginx主进程与原始主进程并行运行,他们共享监听套接字,两个进程都处于活动状态,他们各自的工作进程都在处理流量,然后可以可以指示旧的Master和Worker进程正常退出。

3.5、Nginx的优势

在每个请求一个进程,阻塞式的连接方法中,每个连接都需要大量额外的资源开销,并且会导致频繁的上下文切换;可以尽可能消耗少的内存,每个连接几乎没有额外的开销,Nginx进程数可以设置为CPU核心数,上下文切换相对较少。

那么问题来了,我们自己写网络程序的时候,有没有可以帮助我们提高网络性能的程序框架呢?有,那就是大名鼎鼎的Netty,接下来就来说他。

4、Netty

=======

性能追击:万字长文30+图揭秘8大主流服务器程序线程模型展示

4.1、Netty主从Reactor模式

Netty也不例外,是基于Reactor模型设计和开发的。

Netty采用了主从Reactor模式,主Reactor只负责建立连接,获取已连接套接字,然后把已连接套接字的IO事件转给从Reactor线程进行处理。

性能追击:万字长文30+图揭秘8大主流服务器程序线程模型展示

我们先来大致讲讲Netty中的几个与Reactor有关的抽象概念:

  • Selector:可以理解为一个Reactor线程,内部会通过IO多路复用感知事件的发生,然后把事件交代给Channel进行处理;

  • Channel:注册到Selector中的对象,代表Selector监听的事件,如套接字读写事件;

具体上,Netty抽象出了以下模型进行实现Reactor主从模式:

性能追击:万字长文30+图揭秘8大主流服务器程序线程模型展示

Netty基于Pipeline管道的模式来处理Channel事件,从Netty的使用API中也可以了解到。

4.2、Netty主从Reactor+Worker线程池模式

为了降低具体业务逻辑对从Reactor的影响,我们可以单独把业务逻辑处理放到一个线程池中处理,这样无论是对于监听套接字的事件处理,还是对于已连接套接字事件的处理,都不会因为业务处理程序而导致阻塞了,如下图所示,更详细的说明参考我的博客 IT宅(itzhai.com) 或者公众号 Java架构杂谈(itread) 中的文章更新 网络编程范式:高性能服务器就这么回事 | C10K,Event Loop,Reactor,Proactor :

性能追击:万字长文30+图揭秘8大主流服务器程序线程模型展示

我们可以通过创建一个 DefaultEventExecutorGroup 线程池来处理业务逻辑。

大致程序框架如下图所示:

// 声明一个bossGroup作为主Reactor,本质是一个线程池,每个线程是一个EventLoop

EventLoopGroup bossGroup = new NioEventLoopGroup();

// 声明一个workerGroup作为从Reactor,本质是一个线程池,每个线程是一个EventLoop

EventLoopGroup workerGroup = new NioEventLoopGroup();

// 构建业务处理Group

DefaultEventExecutorGroup defaultEventExecutorGroup =

new DefaultEventExecutorGroup(10,

new ThreadFactory() {

private AtomicInteger threadIndex = new AtomicInteger(0);

@Override

public Thread newThread(Runnable r) {

return new Thread(r, “BusinessThread-” + this.threadIndex.incrementAndGet());

}

});

try {

// 创建服务端启动类

ServerBootstrap bootstrap = new ServerBootstrap();

bootstrap.group(bossGroup, workerGroup)

.channel(NioServerSocketChannel.class)

.childHandler(new ChannelInitializer() {

@Override

protected void initChannel(SocketChannel ch) throws Exception {

// 在pipeline中添加自定义的handler

ch.pipeline().addLast(defaultEventExecutorGroup, new BizHandler());

}

});

ChannelFuture future = bootstrap.bind(port).sync();

future.channel().closeFuture().sync();

} finally {

bossGroup.shutdownGracefully();

workerGroup.shutdownGracefully();

}

Netty是基于NIO的,而Java中的NIO是JDK1.4开始支持,内部是基于IO多路复用实现的,具体的实现思路不再详细说,底层都是IO复用技术,通过Channel借助于Buffer处理感知到的IO事件。

有了NIO为啥还要有Netty?

这是两个不同层次的东西,NIO只是一个IO类库,实现同步非阻塞IO,而Netty是基于NIO实现的高性能网络框架,基于主从Reactor设计的。

NIO类库API复杂,需要处理多线程编程,自己写Reactor模式,并且客户端断线重连、半包读写,失败缓存、网络阻塞和异常码流等问题处理起来难度很大。而Netty对于NIO遇到的这些问题都做了很好的封装,主要优点体现在:

  • API使用简单;

  • 封装度高,功能强大,提供多种编码解码器,解决了TCP拆包粘包问题;

  • 基于Reactor模式实现,性能高,无需再自己实现Reactor了;

  • 商用项目多,经历过很多考验,社区活跃…

5、Redis

=======

性能追击:万字长文30+图揭秘8大主流服务器程序线程模型展示

相信大家已经听过无数遍“Redis是单线程的”这句话了, Redis真的是单线程的吗,又是如何支撑那么大的并发量 ,并且运用到了这么多的互联网应用中的呢?

其实,Redis的单线程指的是Redis内部会有一个主处理线程,充分利用了非阻塞、IO多路复用模型,实现的一个Reactor架构。但是在某些情况下,Redis会生成线程或者子进程来执行某些比较繁重的任务。

5.1、Redis线程模型

还是那个Reactor模型,只不过我们再次踏入了不同的国界,于是又出现了一种新的的表述方式。

Redis基于Reactor模型开发了网络事件处理器,这个处理器被称为文件事件处理器。不过叫什么不重要,重要的是原理都是一样的。以下是Redis的线程模型:

性能追击:万字长文30+图揭秘8大主流服务器程序线程模型展示

这个图基本上涵盖了Redis进程处理的主要事情:

  • 客户端A发起请求建立连接,监听套接字Server Socket建立连接之后,产生一个AE_READABLE事件;

  • 该事件被IO多路复用处理,放入事件队列,最终被文件事件分派器分派给了连接应答处理器进行处理:连接应答处理器处理新连接,将FD1套接字的AE_READABLE事件与命令请求处理器关联起来。

  • 客户端A最终在客户端生成一个已连接套接字FD1;

  • 客户端A发送命令请求,产生一个AE_READABLE事件,该事件被IO多路复用处理,放入事件队列,最终被文件事件分派器分派给了命令请求处理器进行处理:命令请求处理器执行客户端FD1套接字命令操作,得到结果,将结果写入到套接字的回复缓冲区中,准备好响应给客户端;同时将FD1套接字的AE_WRITABLE事件与命令回复处理器关联;

  • 当FD1套接字准备好写的时候,会产生一个AE_WRITABLE事件,该事件被IO多路复用处理,放入事件队列,最终被事件分派器分派给了命令回复处理器进行处理:命令回复处理器把结果输出响应给客户端的FD1已连接套接字;然后将FD1套接字的AE_WRITABLE事件跟命令回复处理器解除关联。

大致一个交互流程就这样完成了,是不是很简单呢。

5.2、为啥Redis单线程也这么高效?

前面已经讲了这么多Reactor模式的好处,相信大家心里也有个底了,大致总结下:

  • Redis是纯内存操作的,所以处理速度非常快,这同时也跟Redis高效的数据结构有关,不过本文重点是讲网络相关的,数据结构不展开讲;

  • Redis的瓶颈不在CPU,而是在内存和网络;

  • 单线程反而避免了上下文切换的开销。

对于开发人员来说,最关注的一点就是:单线程降低了开发的复杂度,再也不需要处理各种静态条件了,就连Hash的惰性Rehash,Lpush等线程不安全的命令都可以进行无锁编程了。

5.3、Redis真的是单线程的吗?

我再问一句大家,Redis真的是单线程的吗,从Reactor模型上来说,单线程肯定会存在瓶颈的;

为此,Redis引入了多线程机制。

Redis 4.0初步引入多线程

在Redis 4.0中,Redis开始使具有更多线程。这个版本仅限于在后台删除对象,其中包括非阻塞的删除操作。UNLINK操作,只会将键从元数据中删除,并不会立刻删除数据,真正的删除操作会在一个后台线程异步执行。

Redis 6.0真正引入多线程

虽然基于Reactor模型,单线程也可以支持很大的并发量,但是要是IO读写多了,待处理的已连接套接字多了,需要执行的命令也多了,那么,单线程依旧是瓶颈,这个时候我们就要引入主从Reactor模型,甚至主从Reactor模型+Worker线程池了。

在Redis 6.0中,如果要开启多线程,可以进行设置:

io-threads 线程数

io-threads-do-reads yes // 默认IO线程只会用于写操作,如果要在读操作和协议解析的时候启用IO线程,则可以设置该选项为yes,但是Redis团队声称它并没有多大帮忙

不过呢,Redis为了避免产生线程并发安全的问题,在执行命令阶段仍然是单线程顺序执行的,只是在网络数据读写和协议解析阶段才用到了多线程。

为了进一步了解这个特性,我们可以阅读以下 redis.conf配置文件的说明。在这里,这个特性被命名为: THREADED I/O ,下面是翻译整理自里面的一些说明。

THREADED I/O

Redis大多是单线程的,但是有一些线程操作,例如UNLINK,执行缓慢的I/O访问等是在后台线程上执行的操作。

将io-threads设置为1只会像传统一样只启用单线程

使用8个以上的线程不会有太大帮助,并且建议实际存在性能问题的时候才使用IO线程,否则就没有必要使用了。

启用IO线程后,我们仅将IO线程用于写操作,即对write(2)系统调用进行线程化并将客户端缓冲区传输到套接字。 但是,也可以使用以下配置指令通过以下方式启用读取线程和协议解析:

io-threads-do-reads yes

通常,线程读取没有太大帮助。

Redis用的是类似单线程版的Reactor + IO线程池(Worker线程池),不过与我们前面提到的单线程Reactor + Worker线程池模式有所不同,再回顾下Reactor + Worker线程池模式:

性能追击:万字长文30+图揭秘8大主流服务器程序线程模型展示

Redis是在所谓的Reactor线程(主线程)中把IO读事件一批一批地交给IO线程池进行读取,读取完毕之后,统一执行所有请求的命令,然后才是一次性把所有请求的响应写到socket,如下图所示:

性能追击:万字长文30+图揭秘8大主流服务器程序线程模型展示

等待队列中的待处理时间平均分给每个IO线程,IO线程池只是负责IO读写和解析数据,IO线程池充分利用了CPU多核处理的能力,提高了IO读写速度。

Redis 6.0真的是单线程的吗?

6、Tomcat

========

性能追击:万字长文30+图揭秘8大主流服务器程序线程模型展示

作为一个Java程序员,怎么能不认识Tomcat呢,Tomcat的线程模型又是怎样的?不用往下看,我们都能猜出Tomcat肯定会利用Reactor模式来优化网络处理,不过这个优化过程却是跟随者技术的发展慢慢演变的。

6.1、Tomcat整体架构

Tomcat是HTTP服务器,同时还是一个Servlet容器,可以执行Java Servlet,并将JavaServer Pages(JSP)和JavaServerFaces(JSF)转换为Java Servlet。

我们先来看看Tomcat各个组件的整体架构。Tomcat采用了分层和模块化的体系结构,如下所示,这个结构有点像套娃,一层套一层的,这也同时是Tomcat server.xml配置文件的层级结构:

性能追击:万字长文30+图揭秘8大主流服务器程序线程模型展示

Server是顶层组件,代表着一个Tomcat实例,在配置文件中一般如下:

Server下面可以包含多个Service,每个服务都有自己的Container和Connector。

  • 6.1.1、Container

Container用于管理各种Servlet,处理Connector传过来的Request请求。

大家可以看到,Container内部若隐若现的好像还有内幕…是的,上图中我把内幕隐藏起来了,接口Container内部,我们可以看到这样的结构:

性能追击:万字长文30+图揭秘8大主流服务器程序线程模型展示

  • Container最顶层是Engine,一个Service只能有一个Engine,用来管理多个站点;

  • Host代表一个站点,一个Engine下可以有多个Host;

  • Context代表一个应用,一个Host下面可以有多个应用;

  • Wrapper封装Servlet,每个应用都有很多Servlet,这个是大家最熟悉的了。

  • 6.1.2、Connector

Connector用于处理请求,处理Socket套接字,把原始的网络数据包装成Request对象给Container进行处理,并封装Response对象用于响应套接字输出。

如上图,一个Service可以有多个Connector, 每个Connector实现不同的连接协议,通过不同的端口提供服务。

这里已经看到我们要关注的重点了,是的,Connector就是处理网络的关键模块,这个模块的效率直接决定了Tomcat的性能!!!

接下来,我们打开Connector潘多拉的盒子,看看里面究竟有什么不可告人的秘密。

话不多说,我直接上图,这么爽快不断附图片的博客还真不多,IT宅(itzhai.com)的Java架构杂谈 算一个,重点来了,这里我们先列出传统的BIO运行模型的组件图:

性能追击:万字长文30+图揭秘8大主流服务器程序线程模型展示

其中 ProtocolHandler 中主要的组件有:

EndPoint

Processor

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加V获取:vip1024b (备注Java)
img

知其然不知其所以然,大厂常问面试技术如何复习?

1、热门面试题及答案大全

面试前做足功夫,让你面试成功率提升一截,这里一份热门350道一线互联网常问面试题及答案助你拿offer

2、多线程、高并发、缓存入门到实战项目pdf书籍

3、文中提到面试题答案整理

4、Java核心知识面试宝典

覆盖了JVM 、JAVA集合、JAVA多线程并发、JAVA基础、Spring原理、微服务、Netty与RPC、网络、日志、Zookeeper、Kafka、RabbitMQ、Hbase、MongoDB 、Cassandra、设计模式、负载均衡、数据库、一致性算法 、JAVA算法、数据结构、算法、分布式缓存、Hadoop、Spark、Storm的大量技术点且讲解的非常深入

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

MQ、Hbase、MongoDB 、Cassandra、设计模式、负载均衡、数据库、一致性算法 、JAVA算法、数据结构、算法、分布式缓存、Hadoop、Spark、Storm的大量技术点且讲解的非常深入**

[外链图片转存中…(img-0HX7n65v-1712578609928)]

[外链图片转存中…(img-qkBmzZ67-1712578609928)]

[外链图片转存中…(img-46H9D0sP-1712578609928)]

一个人可以走的很快,但一群人才能走的更远。如果你从事以下工作或对以下感兴趣,欢迎戳这里加入程序员的圈子,让我们一起学习成长!

AI人工智能、Android移动开发、AIGC大模型、C C#、Go语言、Java、Linux运维、云计算、MySQL、PMP、网络安全、Python爬虫、UE5、UI设计、Unity3D、Web前端开发、产品经理、车载开发、大数据、鸿蒙、计算机网络、嵌入式物联网、软件测试、数据结构与算法、音视频开发、Flutter、IOS开发、PHP开发、.NET、安卓逆向、云计算

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值