- 1、所用的系统承载量、并发能达到多少?
- 2、mq在技术选型时是为了解决什么问题?
- 3、mq如何保证数据的安全性,一个消息推送到mq中,消息发送失败了如何处理
- 4、mq中的消息确认ack机制
- 5、在业务中遇到瓶颈了,如何通过并发或者多线程去进行优化
- 6、如何理解线程和进程
- 7、线程池如何设置
- 8、生产上java服务出现故障了如何处理?
- 9、线程中如何保证线程安全
- 10、hashmap底层原理
- 11、jvm的内存模型分为那几块?(可能还会深入问一些gc的机制)
- 12、在生产上遇到内存溢出问题了如何分析和解决思路
- 13、springcloud中的bean是线程安全的还是不安全?作用域都有哪些?
- 14、对容器是否有了解?
- 15、会写docker镜像么,dockerfile中都需要设置哪些参数?
- 16、启动容器使用哪个命令?
- 17、数据是如何在springcloud如何流转的
- 18、springmvc从接受信息到返回结果是什么过程
- 19、springboot装载过程?
- 20、redis有哪几种部署模式,这几种模式的机制是如何的
- 21、sql缓慢如何调优
- 22、redis集群模式
- 23、mq和kafka的区别
- 24、频道出现full gc,是什么情况导致的?
- 25、java1.8之后jvm有什么不同
1、所用的系统承载量、并发能达到多少?
2、mq在技术选型时是为了解决什么问题?
3、mq如何保证数据的安全性,一个消息推送到mq中,消息发送失败了如何处理
- 持久化
- ACK
- 事务处理
4、mq中的消息确认ack机制
为了保证消息从队列可靠的达到消费者,RabbitMQ提供了消息确认机制(Message Acknowledgement)。消费者在订阅队列时,可以指定autoAck参数,当autoAck参数等于false时,RabbitMQ会等待消费者显式地回复确认信号后才从内存(或磁盘)中移除。当autoAck参数等于true时,RabbitMQ会自动把发送出去的消息置为确认,然后从内存(或磁盘)中删除,而不管消费者是否真正地消费到了这些消息。
采用消息确认机制后,只要设置 autoAck 参数为 false,消费者就有足够的时间处理消息(任务),不用担心处理消息过程中消费者进程挂掉后消息丢失的问题,因为 RabbitMQ 会一直等待持有消息直到消费者显式调用 Basic.Ack 命令为止。
当autoAck 参数为 false 时,对于 RabbitMQ 服务器端而言,队列中的消息分成了两部分:一部分是等待投递给消费者的消息;一部分是已经投递给消费者,但是还没有收到消费者确认信号的消息。如果 RabbitMQ 服务器端一直没有收到消费者的确认信号,并且消费此消息的消费者已经断开连接,则服务器端会安排该消息重新进入队列,等待投递给下一个消费者(也可能还是原来的那个消费者)。
[
](https://blog.csdn.net/pan_junbiao/article/details/112956537)
5、在业务中遇到瓶颈了,如何通过并发或者多线程去进行优化
6、如何理解线程和进程
进程:是并发执行的程序在执行过程中分配和管理资源的基本单位,是一个动态概念,竞争计算机系统资源的基本单位。
线程:是进程一个执行单元,比进程更小的独立运行的基本单位。线程也被称为轻量级进程。
线程和进程的区别:
- 地址空间
线程共享本进程的地址空间,而进程之间是独立的地址空间。
- 资源
线程共享本进程的资源,如内存、I/O、CPU等,不利于资源的管理和保护,而进程之间的资源是独立的,能很好的进行资源管理和保护。
- 健壮性
多进程要比多线程健壮,一个进程崩溃后,在保护模式下不会对其他进程产生影响,但是一个线程崩溃整个进程都死掉。
- 执行过程
每个独立的进程有一个程序运行的入口、顺序执行序列和程序入口,执行开销大。
但是线程不能独立运行,必须依存在应用程序中,由应用程序提供多个线程执行控制,执行开销小。
- 可并发性
两者均可并发执行。
- 切换时
进程切换时,消耗的资源大,效率高。所以涉及到频繁的切换时,使用线程要好于进程。同样如果要求同时进行并且又要共享某些变量的并发操作,只能用线程不能用进程。
- 其他
线程是处理器调度的基本单元,但进程不是。
何时使用多进程,何时使用多线程?
对资源的管理和保护要求高,不限于开销和效率时,使用多进程。
要求效率高,频繁切换时,资源的保护管理要求不是很高时,使用多线程。
7、线程池如何设置
- corePoolSize:核心线程数
- maximumPoolSize:最大线程数
- keepAliveTime:线程空闲时间
- queueCapacity:任务队列容量(阻塞队列)
- allowCoreThreadTimeout:允许核心线程超时
- rejectedExecutionHandler:任务拒绝处理器
8、生产上java服务出现故障了如何处理?
9、线程中如何保证线程安全
- 使用线程安全的类
- 使用synchronized同步代码块,或者用Lock锁
由于线程安全问题,使用synchronized同步代码块 原理:当两个并发线程访问同一个对象object中的这个synchronized(this)同步代码块时,一个时间内只能有一个线程得到执行。 另一个线程必须等待当前线程执行完这个代码块以后才能执行该代码块。
- 多线程并发情况下,线程共享的变量改为方法局部级变量
10、hashmap底层原理
HashMap基于Hash表的Map接口实现。
Hash表
- JDK8之前,底层采用数组+链表实现
- JDK8之后,底层进行了优化,由数组+链表+红黑树实现
- HashMap的节点:HashMap是一个集合,键值对的集合,源码中每个节点用Node
表示
Node是一个内部类,这里的key为键,value为值,next指向下一个元素,可以看出HashMap中的元素不是一个单纯的键值对,还包含下一个元素的引用。
- HashMap的数据结构:HashMap的数据结构为 数组+(链表或红黑树)
为什么采用这种结构来存储元素?
数组的特点:查询效率高,插入删除效率低
链表的特点:查询效率低,插入删除效率高
在HashMap底层使用数组加(链表或红黑树)的结构完美解决了数组和链表的问题,使得查询和插入,删除的效率都很高。
11、jvm的内存模型分为那几块?(可能还会深入问一些gc的机制)
- 程序计数器(Program Counter Register)
程序计数器(Program Counter Register)是一块较小的内存空间,它可以看作是当前线程所执行的字节码的行号指示器。在虚拟机概念模型里(概念模型,各种虚拟机可能会通过一些更高效的方式实现),字节码解释器工作时就是通过改变这个计数器的值来选取下一条需要执行的字节码指令:分支、跳转、循环、异常处理、线程恢复等基础操作都会依赖这个计数器来完成。每个线程都有独立的程序计数器,用来在线程切换后能恢复到正确的执行位置,各条线程之间的计数器互不影响,独立存储。所以它是一个“线程私有”的内存区域。此内存区域是唯一一个在JVM规范中没有规定任何OutOfMemoryError情况的区域。
- 虚拟机栈(VM Stack)
JVM栈是线程私有的内存区域。它描述的是java方法执行的内存模型,每个方法执行的同时都会创建一个栈帧(Stack Frame)用于存储局部变量表、操作数栈、动态链接、方法出口等信息。每个方法从调用直至完成的过程,都对应着一个栈帧从入栈到出栈的过程。每当一个方法执行完成时,该栈帧就会弹出栈帧的元素作为这个方法的返回值,并且清除这个栈帧,Java栈的栈顶的栈帧就是当前正在执行的活动栈,也就是当前正在执行的方法。就像是组成动画的一帧一帧的图片,方法的调用过程也是由栈帧切换来产生结果。
- 本地方法栈(Native Method Stack)
本地方法栈和虚拟机栈所发挥的作用是很相似的,它们之间的区别不过是虚拟机栈为虚拟机执行Java方法(字节码)服务,而本地方法栈则为虚拟机使用到的Native方法服务。Sun HotSpot 直接就把本地方法栈和虚拟机栈合二为一。本地方法栈也会抛出StackOverflowError和OutOfMemoryError异常。
- 堆(Heap)
Heap是OOM故障最主要的发源地,它存储着几乎所有的实例对象,堆由垃圾收集器自动回收,堆区由各子线程共享使用;通常情况下,它占用的空间是所有内存区域中最大的,但如果无节制地创建大量对象,也容易消耗完所有的空间;堆的内存空间既可以固定大小,也可运行时动态地调整,通过参数-Xms设定初始值、-Xmx设定最大值。
- 方法区(Method Area)
方法区是被所有线程共享的内存区域,用来存储已被虚拟机加载的类信息、常量、静态变量、JIT(just in time,即时编译技术)编译后的代码等数据。运行时常量池是方法区的一部分,用于存放编译期间生成的各种字面常量和符号引用。
12、在生产上遇到内存溢出问题了如何分析和解决思路
线上故障分析的原则是首先要采取措施快速恢复故障对业务的影响,然后才是采集信息、分析定位问题,并最终给出解决方法。
如何快速恢复业务
通常线上的故障会对业务造成重大影响,影响用户体验,故如果线上服务器出现故障,应规避对业务造成影响,但不能简单的重启服务器,因为需要尽可能保留现场,为后续的问题分析打下基础。
通常的做法是隔离故障服务器。
如何快速规避对业务的影响,并能保留现场呢?
通常线上服务器是集群部署,一个好的分布式负载方案会自动剔除故障的机器,从而实现高可用架构,但如果未被剔除,则需要运维人员将故障服务器进行剔除,保留现场进行分析。
发生内存泄露,通常情况下是由于代码的原因造成的,一般无法立即对代码进行修复,很容易会发送连锁反应造成应用服务器一台一台接连宕机,故障面积会慢慢扩大,针对此种情况,应快速定位发生内存泄露的原因,将该服务进行降级,避免对其他服务造成影响。最简单的降级方法是根据F5(Nginx)转发策略,对该功能定向到一个单独的集群,与其他流量进行隔离,确保其他业务不受牵连,给故障排查、解决提供宝贵的缓冲时间。
分析解决问题
首先可以通过查看日志,确定是哪种内存溢出,堆内存溢出可发生的地方:
Java heap space(堆空间)、perm space(持久代)
收集内存溢出Dump文件
收集Dump文件有两种方式:
设置jvm启动参数
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/opt/jvmdump
在每次发生内存溢出时,JVM会自动将堆转储,dump文件存放在-XX:HeapDumpPath指定的路径下。
使用jmap命令收集
通过jmap -dump:live,format-b,file=/opt/jvm/dump.hprof pid。
分析Dump文件
在获取Dump文件后,可以使用工具MAT(MemoryAnalyzer)进行分析。
13、springcloud中的bean是线程安全的还是不安全?作用域都有哪些?
不安全
因为SpringIOC容器本身没有提供Bean的线程安全策略,所有Spring容器中的Bean本身不具备线程安全的特性,现在结合具体的作用域(scope)去研究。
- singleton(单例):默认作用域,SpringIOC中仅存在一个Bean实例,以单例Bean的方式存在;
- prototype(原型):每次从容器中getBean()时,都返回一个新的实例。等于执行new Bean();
- request(请求):每次Http请求创建一个新对象;
- session(会话):同一个会话共享一个实例,不同会话使用不同实例;
- global-session(全局会话):所有会话共享一个实例。
14、对容器是否有了解?
15、会写docker镜像么,dockerfile中都需要设置哪些参数?
16、启动容器使用哪个命令?
启动容器
docker start [container-name/id]
停止容器
docker stop [container-name/id]
停止所有正在运行的容器
docker stop $(docker ps -aq)
列出Docker容器
docker ps -a
或
docker container ls -a
仅列出正在运行的Docker容器
docker ps
或
docker container ls
仅列出已停止的Docker容器
docker container ls -f "status=exited"
17、数据是如何在springcloud如何流转的
18、springmvc从接受信息到返回结果是什么过程
- 客户端请求提交到 DispatcherServlet。
- 由 DispatcherServlet 控制器寻找一个或多个 HandlerMapping,找到处理请求的 Controller。
- DispatcherServlet 将请求提交到 Controller。
- Controller 调用业务逻辑处理后返回 ModelAndView。
- DispatcherServlet 寻找一个或多个 ViewResolver 视图解析器,找到 ModelAndView 指定的视图。
- 视图负责将结果显示到客户端。
19、springboot装载过程?
20、redis有哪几种部署模式,这几种模式的机制是如何的
- 单机模式
- 主从模式
- 哨兵模式
- 集群方式
21、sql缓慢如何调优
整体思路
- 根据慢日志定位慢查询sql
- 使用explain等工具分析sql
- 修改sql或者尽量让sql走索引
具体实现
- 怎么查询慢日志
1)show variables like ‘%que%’, 查询变量
show variables like '%quer%';
long_query_time:慢日志阈值,超过才会被记录
slow_query_log:打开/关闭慢日志
slow_query_log_file:慢日志记录的位置
2) show status like ‘%slow_queries%’, 慢查询的数量
show status like '%slow_queries%';
3) set global slow_query_log = on; 打开慢查询
4)set global long_query_time = 1; 设置慢查询的时间阈值为:1s
设置完之后需要重新连接数据库,才能生效
5)假设下面这条查询产生慢查询(200万条数据)
select count(id) from person_info_large order by name desc;
6) 再次执行show status like ‘%slow_queries%’
7) 通过终端去查看该日志
- 使用explain分析
在分析查询性能的时候,关键字一般放在select的前面,用于描述mysql如何执行操作
1)查询
explain select name from person_info_large order by name desc;
id标明sql的执行顺序(越大越先执行)
2)type字段和Extra字段
type: 表示mysql找到数据行的方式
system>const>eq_ref>ref>fulltext>ref_or_null>index_merge
>unique_subquery>index_subquery>range>index>all
index/all表示全表扫描,是最慢的,每次看到这两个要特别注意。
extra:
可以获取更为详细的信息:
出现以下两项表示mysql无法使用索引,应尽可能优化
- Using filesort
表示mysql会对结果使用一个外部索引排序,而不是从表里按索引次序读到相关内容。可能在内存或者磁盘上进行排序。MySQL中无法利用索引完成的排序操作称为“文件排序”
- Using temporary
表示mysql在对查询结果排序时使用临时表。常见于排序order by和分组查询group by。
22、redis集群模式
Redis支持三种集群模式:
- 主从复制模式
- Sentinel(哨兵)模式
- Cluster模式
主从复制
Redis提供了复制(replication)功能,可以实现当一台数据库中的数据更新后,自动将更新的数据同步到其他数据库上。
在复制的概念中,数据库分为主数据库(master)和从数据库(slave)。主数据库可以进行读写操作,当写操作导致数据变化时会自动将数据同步给从数据库。而从数据库一般是只读的,并接受主数据库同步过来的数据。一个主数据库可拥有多个从数据库,而一个从数据库只能拥有一个主数据库。
总结:引入主从复制机制的目的有两个
- 一个是读写分离,分担“master”的读写压力
- 一个是方便做容灾恢复
主从复制优点
- 支持主从复制,主机会自动将数据同步到从机,可以进行读写分离;
- 为了分载 Master 的读操作压力,Slave 服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成;
- Slave 同样可以接受其它 Slaves 的连接和同步请求,这样可以有效的分载 Master 的同步压力;
- Master Server 是以非阻塞的方式为 Slaves 提供服务。所以在 Master-Slave 同步期间,客户端仍然可以提交查询或修改请求;
- Slave Server 同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据;
主从复制缺点
- Redis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复(也就是要人工介入);
- 主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题,降低了系统的可用性;
- 如果多个 Slave 断线了,需要重启的时候,尽量不要在同一时间段进行重启。因为只要 Slave 启动,就会发送sync 请求和主机全量同步,当多个 Slave 重启的时候,可能会导致 Master IO 剧增从而宕机。
- Redis 较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂;
Sentinel(哨兵)模式
Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。
哨兵模式的作用:
- 通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器;
- 当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机;
哨兵模式的工作方式:
- 每个Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的 Master 主服务器,Slave 从服务器以及其他Sentinel(哨兵)进程发送一个 PING 命令。
- 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值, 则这个实例会被 Sentinel(哨兵)进程标记为主观下线(SDOWN)
- 如果一个 Master 主服务器被标记为主观下线(SDOWN),则正在监视这个 Master 主服务器的所有 Sentinel(哨兵)进程要以每秒一次的频率确认 Master 主服务器的确进入了主观下线状态
- 当有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认 Master 主服务器进入了主观下线状态(SDOWN), 则 Master 主服务器会被标记为客观下线(ODOWN)
- 在一般情况下, 每个 Sentinel(哨兵)进程会以每 10 秒一次的频率向集群中的所有 Master 主服务器、Slave 从服务器发送 INFO 命令。
- 当 Master 主服务器被 Sentinel(哨兵)进程标记为客观下线(ODOWN)时,Sentinel(哨兵)进程向下线的 Master 主服务器的所有 Slave 从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。
- 若没有足够数量的 Sentinel(哨兵)进程同意 Master主服务器下线, Master 主服务器的客观下线状态就会被移除。若 Master 主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master主服务器的主观下线状态就会被移除。
哨兵模式的优缺点:
优点:
- 哨兵模式是基于主从模式的,所有主从的缺点,哨兵模式都具有;
- 主从可以自动切换,系统更健壮,可用性更高(可以看作自动版的主从复制)。
缺点:
- Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。
Cluster集群模式(Redis官方)
Redis Cluster是一种服务器Sharding技术,3.0版本开始正式提供。
Redis的哨兵模式基本可以实现高可用,读写分离,但是这种模式下Redis服务器都存储相同的数据,很浪费内存,所以在redis3.0上加入了Cluster集群模式,实现了Redis的分布式存储,也就是说每台Redis节点上存储不同的内容。
Redis 集群的主从复制模型
为了保证高可用,redis-cluster集群引入了主从复制模型,一个主节点对应一个或者多个从节点,当主节点宕机的时候,就会启用从节点。当其它主节点 ping 一个主节点 A 时,如果半数以上的主节点与 A 通信超时,那么认为主节点 A 宕机了。如果主节点 A 和它的从节点 A1 都宕机了,那么该集群就无法再提供服务了。
集群的特点
- 所有的 redis 节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。
- 节点的 fail 是通过集群中超过半数的节点检测失效时才生效。
- 客户端与 Redis 节点直连,不需要中间代理层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
23、mq和kafka的区别
RabbitMQ和kafka的区别
- 语言不同
RabbitMQ是由内在高并发的erlang语言开发,用在实时的对可靠性要求比较高的消息传递上。
kafka是采用Scala语言开发,它主要用于处理活跃的流式数据,大数据量的数据处理上。
- 结构不同
RabbitMQ采用AMQP(Advanced Message Queuing Protocal,高级消息队列协议)是一个进程间传递异步消息的网络协议。
RabbitMQ的broker由Exchange, Binding, queue组成
kafka采用mq结构:broker有part分区的概念
- Broker与Consume交互方式不同
RabbitMQ 采用push的方式
kafka采用pull的方式
- 在集群负载均衡方面
RabbitMQ的负载均衡需要单独的loadbalancer进行支撑
kafka采用zookeeper对集群中的broker、consumer进行管理
kafka是LinkedIn开源的分布式发布-订阅消息系统。Kafka主要特点是基于Pull的模式来处理消息消费,追求高吞吐量,一开始的目的就是用于日志收集和传输。0.8版本开始支持复制,不支持事务,对消息的重复、丢失、错误没有严格要求,适合产生大量数据的互联网服务的数据收集业务。
RabbitMQ是使用Erlang语言开发的开源消息队列系统,基于AMQP协议来实现。AMQP的主要特征是面向消息、队列、路由(包括点对点和发布/订阅)、可靠性、安全。AMQP协议更多用在企业系统内,对数据一致性、稳定性和可靠性要求很高的场景,对性能和吞吐量的要求还在其次。
RabbitMQ比kafka可靠,kafka更适合IO高吞吐的处理,比如ELK日志收集。
Kafka和RabbitMQ一样是通用意图消息代理,他们都是以分布式部署为目的。但是他们对消息语义模型的定义的假设是非常不同的。
a. 以下场景比较适合使用Kafka
如果有大量的事件(10万以上/秒),你需要以分区的、顺序的,至少传递成功一次到混杂了在线和打包消费的消费者,希望能重读消息,你能接受目前是有限的节点级别高可用就考虑kafka。
b. 以下场景比较适合使用RabbitMQ
如果是较少的事件(2万以上/次)并且需要通过复杂的路由逻辑去找到消费者,你希望消息传递是可靠的,并不关心消息传递的顺序,而且需要现在就支持集群-节点级别的高可用就可以考虑RabbitMQ。
24、频道出现full gc,是什么情况导致的?
系统承载高并发请求,或者处理数据量过大,导致Young GC很贫乏,而且每次Young GC过后存活对象太多,内存分配不合理,Survivor区过小,导致对象频繁进入老年代,频繁触发Full GC。
Full GC触发条件是老年代空间不足,所以追因的方向就是导致老年代空间不足的原因:
大量对象频繁进入老年代+老年代空间释放不掉。
- 系统并发高、执行耗时过长,或者数据量过大,导致 young gc频繁,且gc后存活对象太多,但是survivor 区存放不下(太小 或 动态年龄判断) 导致对象快速进入老年代 老年代迅速堆满
- 发程序一次性加载过多对象到内存 (大对象),导致频繁有大对象进入老年代 造成full gc
- 存在内存溢出的情况,老年代驻留了大量释放不掉的对象, 只要有一点点对象进入老年代 就达到 full gc的水位了
- 元数据区加载了太多类 ,满了 也会发生 full gc
- 堆外内存 direct buffer memory 使用不当导致
- 也许, 你看到老年代内存不高 重启也没用 还在频繁发生full gc, 那么可能有人作妖,在代码里搞执行了 System.gc();
——————————- 知识点:-———————————-
Young space:年轻代(新生代),保存生命周期较短的对象
Tenured space:老年代(年老代),保存生命周期较长的对象
Minor GC:发生在Young space中的GC
Major GC:发生在老年代Tenured space中的GC
STW(stop the world):指的是用户线程在运行至安全点(safe point)或安全区域(safe region)之后,就自行挂起,进入暂停状态,对外的表现就是卡顿,而不论何种gc算法,不论是minor gc还是major gc都会STW,区别只在于STW的时间长短。
Full GC:无官方定义,通常意义上而言指的是一次特殊GC的行为描述,这次GC会回收整个堆的内存,包含老年代,新生代,metaspace等。
但是实际情况中,我们主要看的是gc.log日志,其中也会发现在部分gc日志头中也有Full GC字眼,此处表示含义是在这次GC的全过程中,都是STW的状态,也就是说在这次GC的全过程中所有用户线程都是处于暂停的状态。
[
](https://blog.csdn.net/weixin_39309402/article/details/104756815)
25、java1.8之后jvm有什么不同
jdk1.8及之后,去除了永久代,本地内存的元空间(Metaspace)取代
为什么去掉永久代?
- 永久代在jvm中,合适的大小难以确定(元空间分配在本地内存,无需考虑大小)
- 对永久代调优很困难