java场景和解法
创建一个只读列表,不希望被修改
Collections.singletonList()方法,接收一个参数,返回一个只包含这个参数的列表,无法通过add等方法修改,若尝试该操作会抛异常。
Arrays.asList()方法,同样无法进行add等操作。
服务
常见的耗时操作:
-
锁/分布式锁/同步锁
-
sql操作,连接耗时
日志打印出现明显的时间间隔,可能的原因:
-
发生了线程切换,换其他线程执行其他任务了。(线程太多了)
-
日志打印太多了,压测5分钟日志量500M。(记得日志打印太多是有很大影响的)
-
STW。(但是日志还在输出,所以前两种可能性很高,而且一般不会停顿百毫秒)
服务器变慢
三种可能:CPU利用率、磁盘I/O效率、内存瓶颈。
cpu利用率过高或过低
-
过高:直观表现是响应变慢,原因是需要处理的任务太多。问题定位:利用top指令查询cpu占用高的进程,看其中活跃的线程,通过jstack打印线程日志,排查原因。
-
-
使用top查看cpu占用高的进程(PID)
-
使用ps -mp命令找到占用CPU高的线程ID(TID)
-
使用printf命令将线程ID转为十六进制的:printf "%x\n" TID
-
使用jstack命令输出线程运行状态的日志信息,jstack的三个参数,PID,TID -A和一个数字,数字代表输出日志的行数:jstack PID grep TID -A10
-
-
过低:说明cpu利用率不够,可以考虑增加线程
磁盘I/O效率不够
-
出现场景:程序需要读写磁盘,依赖的第三方组件对磁盘进行持久化操作,此时可能会成为程序性能瓶颈;还可以通过cpu和负载的非线性关系体现,当负载增大后系统吞吐不能有效增大,且cpu利用率未能线性增高,有可能是磁盘性能不够
-
排查:iostat指令查看,如果磁盘负载高,可以采用一些补救方法:借助缓存;采用顺序写;使用mmap代替read/write,减少内存拷贝次数
内存瓶颈
-
出现场景:内存设置不合理,应用需要频繁进行磁盘I/O
-
排查:内存使用率过高时,用dump命令查看堆内存,用MAT工具分析,查看大对象,并看是否存在内存泄漏。如果用 dump 命令查出的堆内存文件正常,则可以考虑是堆外内存被大量使用导致出现问题,此时需要借助操作系统的pmap命令查出进程的内存分配情况。如果CPU和内存使用率都很正常,那么就需要进一步开启GC日志,分析用户线程暂停的时间、各部分内存区域GC次数和时间等指标,这里可以借助jstat命令或可视化工具GCEasy等。如果问题出在GC上,则考虑是不是内存不足,然后根据垃圾对象的特点进行参数调优,使用更适合的垃圾收集器,用jstack命令分析各个线程的状态。如果问题比较隐蔽,则考虑是否开启JMX,使用 visualmv 等可视化工具进行远程监控与分析。
线上服务器快扛不住了怎么办
lambda表达式的一些场景
-
表达式内部引用的外部局部变量需要具备以下特点
-
-
声明为final
-
局部变量在外部没有被更改过
-
局部变量在内部也没有被显示的更改(更换值,更换指向的对象)
-
所以java的局部变量若没有被更改,也为隐性final类型
解决方法:用数组/list/Map等引用类型包一下,这样可以对引用类型内部的值修改而不影响lambda表达式的引用。
java集合相关
-
集合判断是否相等
-
list/set判断,直接用equals,会自动比较集合中的内容
ArrayList<Integer> list1 = new ArrayList<Integer>() {{ add(1); add(2); add(3); }}; System.out.println(list1.equals(Arrays.asList(1, 2, 3))); HashSet<Integer> set1 = new HashSet<Integer>() {{ add(1); add(2); add(3); }}; System.out.println(set1.equals(new HashSet<>(list1)));
-
-
集合取差集
list1.removeAll(list2),但是注意此方法会改变list1的内容,若不想改变,先进行拷贝再用该方法
-
list转化为用逗号分割的字符串
-
String.join(",", list);
-
-
字符串转list
-
split方法,注意:用"."、"\"、"|"分割时需要用转义字符,如:split("\\.")
-
类相关
java方法
实现默认参数
-
方法重载实现
-
可变参数(Varargs):在方法内部检测是否提供了足够的参数,若没有就使用默认值
public void foo(int a, Stirng... b){ String bValue = (b.length > 0) ? b[0] : "default"; }
-
Builder模式,很多参数有默认值的情况,只指定关心的参数,其他的使用默认值
java读取文件
Files类
一次性加载到内存中,注意oom
-
readAllLines
-
readAllyBytes
java的Stream
来源:可以由数组和集合产生
分类:stream(顺序)和 parallelStream(并行)
stream流返回map:stream().collect(Collectors.groupingBy(BatchProcess::getBatchName))
foreach循环的用法,map的entrySet中的每个entry
SSM
java的事务注解
详解:https://www.cnblogs.com/better-farther-world2099/articles/14982412.html
Transactional注解:可用于类、方法、接口
-
作用于类:
-
方法:
-
接口:
@Transactional(value = "group_tx", rollbackFor = Exception.class)
注解失效的场景:Spring同一个类中方法调用注解失效_springboot自定义注解在同一个类上的第二次调用方法不生效-CSDN博客
-
注解加事务的机制,以及什么情况下事务注解会失效
spring的aop注解,
存储引擎
ES
Elasticsearch(ES):Elasticsearch是一个基于Lucene的搜索服务器,提供具有分布式能力的搜索,采用restful风格进行查询,常用于存储、搜索和分析大量的日志、文档等非结构化和半结构化的数据。
mysql
存储结构化数据。
mysql和ES的同步
实现方式:
-
同步双写
-
简单方便,实时性强
-
硬编码,不好修改,性能差
-
-
借助 MQ实现异步的写入(针对多源写入的场景)
-
1和2都存在硬编码的情况,可以考虑用定时器实现(实时性不高的情况)
步骤
-
增加timestap字段,只有CRUD操作会更改该值
-
增加定时器程序,按一定时间扫描指定表,将数据一条一条写入ES
-
注意:数据库存在轮询压力
-
-
基于binlog的同步(实时性较好,不存在硬编码)
步骤
-
读取binlog日志
-
转为MQ
-
编写一个 MQ 消费程序;
-
不断消费 MQ,每消费完一条消息,将消息写入到 ES 中。
-
常用数据迁移工具
-
canal
-
基于mysql的主从复制原理实现
-
-
阿里云DTS(付费)
-
databus(开源)
Databus 是一个低延迟、可靠的、支持事务的、保持一致性的数据变更抓取系统
-
flink:有界数据流和无界数据流上进行有状态计算分布式处理引擎和框架。
-
主要特点是能够在分布式环境中进行高效、精确、可扩展的数据流处理。
-
既可以处理实时的数据流,也可以处理批量的数据
-
json字符串解析
gson库
fromJSON,string类型解析为其他类型
toJson,其他类型转为json字符串
地理信息编码和计算,geohash
-
计算地理编码的hash值,由二维经纬度转换为string字符串,便于存储和查询
-
geohash的长度决定了它的精度,长度越短,精度越低,区域越大
-
原理:经度从-180到180,按照二分法划分,是编码后的前半部分,精度从-90到90,编码的后半部分