- [ ] mysql主从配置
- [ ] mybatis自动生成代码
- [ ] 读写分离,与主从配置相关联
- [ ] 分布式redis缓存
- [ ] tomcat session共享、session绑定
- [ ] 分布式锁:redis、mysql
jvm系列
本文字数: 4.2k 阅读时长 ≈ 4 分钟
什么是类的加载
类的加载指的是将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个java.lang.Class对象,用来封装类在方法区内的数据结构。类的加载的最终产品是位于堆区中的Class对象,Class对象封装了类在方法区内的数据结构,并且向Java程序员提供了访问方法区内的数据结构的接口。
类的生命周期
- 加载,查找并加载类的二进制数据,在Java堆中也创建一个java.lang.Class类的对象
- 连接,连接又包含三块内容:验证、准备、初始化。1)验证,文件格式、元数据、字节码、符号引用验证;2)准备,为类的静态变量分配内存,并将其初始化为默认值;3)解析,把类中的符号引用转换为直接引用
- 初始化,为类的静态变量赋予正确的初始值
- 使用,new出对象程序中使用
- 卸载,执行垃圾回收
类加载器
启动类加载器:Bootstrap ClassLoader,负责加载存放在JDK\jre\lib(JDK代表JDK的安装目录,下同)下,或被-Xbootclasspath参数指定的路径中的,并且能被虚拟机识别的类库
扩展类加载器:Extension ClassLoader,该加载器由sun.misc.Launcher$ExtClassLoader实现,它负责加载DK\jre\lib\ext目录中,或者由java.ext.dirs系统变量指定的路径中的所有类库(如javax.*开头的类),开发者可以直接使用扩展类加载器。
应用程序类加载器:Application ClassLoader,该类加载器由sun.misc.Launcher$AppClassLoader来实现,它负责加载用户类路径(ClassPath)所指定的类,开发者可以直接使用该类加载器
双亲委派模型
\- 全盘负责,当一个类加载器负责加载某个Class时,该Class所依赖的和引用的其他Class也将由该类加载器负责载入,除非显示使用另外一个类加载器来载入 - 父类委托,先让父类加载器试图加载该类,只有在父类加载器无法加载该类时才尝试从自己的类路径中加载该类 - 缓存机制,缓存机制将会保证所有加载过的Class都会被缓存,当程序中需要使用某个Class时,类加载器先从缓存区寻找该Class,只有缓存区不存在,系统才会读取该类对应的二进制数据,并将其转换成Class对象,存入缓存区。这就是为什么修改了Class后,必须重启JVM,程序的修改才会生效
方法区和堆是所有线程共享的内存区域;而java栈、本地方法栈和程序计数器是运行是线程私有的内存区域。
Java堆(Heap),是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
方法区(Method Area),方法区(Method Area)与Java堆一样,是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
程序计数器(Program Counter Register),程序计数器(Program Counter Register)是一块较小的内存空间,它的作用可以看做是当前线程所执行的字节码的行号指示器。
JVM栈(JVM Stacks),与程序计数器一样,Java虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法被执行的时候都会同时创建一个栈帧(Stack Frame)用于存储局部变量表、操作栈、动态链接、方法出口等信息。每一个方法被调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
本地方法栈(Native Method Stacks),本地方法栈(Native Method Stacks)与虚拟机栈所发挥的作用是非常相似的,其区别不过是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务,而本地方法栈则是为虚拟机使用到的Native方法服务。
对象分配规则
对象优先分配在Eden区,如果Eden区没有足够的空间时,虚拟机执行一次Minor GC。
大对象直接进入老年代(大对象是指需要大量连续内存空间的对象)。这样做的目的是避免在Eden区和两个Survivor区之间发生大量的内存拷贝(新生代采用复制算法收集内存)。
长期存活的对象进入老年代。虚拟机为每个对象定义了一个年龄计数器,如果对象经过了1次Minor GC那么对象会进入Survivor区,之后每经过一次Minor GC那么对象的年龄加1,知道达到阀值对象进入老年区。
动态判断对象的年龄。如果Survivor区中相同年龄的所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代。
空间分配担保。每次进行Minor GC时,JVM会计算Survivor区移至老年区的对象的平均大小,如果这个值大于老年区的剩余值大小则进行一次Full GC,如果小于检查HandlePromotionFailure设置,如果true则只进行Monitor GC,如果false则进行Full GC。
对象存活判断
判断对象是否存活一般有两种方式:
引用计数:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计数为0时可以回收。此方法简单,无法解决对象相互循环引用的问题。
可达性分析(Reachability Analysis):从GC Roots开始向下搜索,搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的,不可达对象。
GC算法
GC最基础的算法有三种:标记 -清除算法、复制算法、标记-压缩算法,我们常用的垃圾回收器一般都采用分代收集算法。
标记 -清除算法,“标记-清除”(Mark-Sweep)算法,如它的名字一样,算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收掉所有被标记的对象。
复制算法,“复制”(Copying)的收集算法,它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。
标记-压缩算法,标记过程仍然与“标记-清除”算法一样,但后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存
分代收集算法,“分代收集”(Generational Collection)算法,把Java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。
垃圾回收器
Serial收集器,串行收集器是最古老,最稳定以及效率高的收集器,可能会产生较长的停顿,只使用一个线程去回收。
ParNew收集器,ParNew收集器其实就是Serial收集器的多线程版本。
Parallel收集器,Parallel Scavenge收集器类似ParNew收集器,Parallel收集器更关注系统的吞吐量。
Parallel Old 收集器,Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和“标记-整理”算法
CMS收集器,CMS(Concurrent Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器。
G1收集器,G1 (Garbage-First)是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高概率满足GC停顿时间要求的同时,还具备高吞吐量性能特征
在Java语言中,GC Roots包括:
- 虚拟机栈中引用的对象。
- 方法区中类静态属性实体引用的对象。
- 方法区中常量引用的对象。
- 本地方法栈中JNI引用的对象。
调优命令
Sun JDK监控和故障处理命令有jps jstat jmap jhat jstack jinfo
- jps,JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程。
- jstat,JVM statistics Monitoring是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。
- jmap,JVM Memory Map命令用于生成heap dump文件
- jhat,JVM Heap Analysis Tool命令是与jmap搭配使用,用来分析jmap生成的dump,jhat内置了一个微型的HTTP/HTML服务器,生成dump的分析结果后,可以在浏览器中查看
- jstack,用于生成java虚拟机当前时刻的线程快照。
- jinfo,JVM Configuration info 这个命令作用是实时查看和调整虚拟机运行参数。
主要关注点:
GC日志分析
调优命令
- 调优工具
调优工具
- 常用调优工具分为两类,jdk自带监控工具:jconsole和jvisualvm,第三方有:MAT(Memory Analyzer Tool)、GChisto。
- jconsole,Java Monitoring and Management Console是从java5开始,在JDK中自带的java监控和管理控制台,用于对JVM中内存,线程和类等的监控
- jvisualvm,jdk自带全能工具,可以分析内存快照、线程快照;监控内存变化、GC变化等。
- MAT,Memory Analyzer Tool,一个基于Eclipse的内存分析工具,是一个快速、功能丰富的Java heap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗
- GChisto,一款专业分析gc日志的工具
日志分析脚本
本文字数: 2.2k 阅读时长 ≈ 2 分钟
sed编辑器
不修改原内容的行级别流编辑器
sed ‘s/baidu /earyant/‘ access.log | head -10
将日志文件中的baidu替换成earyant输出
s表示执行的事文本替换命令sed -n ‘2,6p’ access.log
-n表示只输出指定的行,’2,6p’表示选择的事第二行到第六行
sed ‘/earyant/d’ access.log
d表示执行文本删除命令,将包含earyant的行删除
sed ‘=’ access.log
显示文本行号
sed -e ‘i\head’ access.log | head -10
在行首插入文本
sed -e ‘a\end’ access.log | head -10
在文末追加文本
sed -e ‘/baidu/c\hello’ access.log | head -10
c命令对文本进行替换,查找/baidu/匹配的行,用hello对匹配的行进行替换,与s不同的是,这个替换行,s是替换单词
- sed -n ‘1,5p;1,5=’ access.log
多条命令,分号隔开
awk
- awk ‘{print $1}’ access.log | head -10
打印指定的列
- awk ‘/baidu/{print $5,%6}’ access.log | head -10
筛选指定的行,并且打印出其中一部分列
awk ‘length{$0} > 40 {print $3}’ access.log | head -10
$0 表示当前的行,length($0)获取当前行的长度,print $3 打印出第三列
awk ‘{line = sprintf (“method:%s,response:%s”,$3,$7); print line}’ access.log | head -10
定义line接收sprintf输出,sprintf用户格式化输出第三行的请求式和第七行的响应时间
shell
- 系统load超过2或者磁盘利用率超过85%报警:
1 | #!/bin/bash |
- 读取日志文件,对字段切割,插入到sql。
db:
1 | create table access_log( |
shell:
1 | #!/bin/bash |
日志分析常用命令
本文字数: 1.5k 阅读时长 ≈ 1 分钟
查看文件的内容
cat:正序查看
cat access.log
tac:倒序查看
tac access.log
分页显示文件
more
more access.log
Enter显示文件下一行
空格显示下一页
F显示下一屏内容
B显示上一屏内容less
/GET 查找GET字符串
显示文件尾
tail
tail -f -n 500 access.log
-f 持续查看
-n 显示最后n行
显示文件头
- head
head -n2 access.log
内容排序
sort
sort -n -r access.log
-n 按照数字排序
-r 逆序排序sort -k 2 -t “ “ -n access.log
-k 指定排序的列
-t 指定列分隔符
-n 按照数字排序
字符统计
wc
wc -l access.log
-l 统计文件中的行数
wc -c access.log
-c 显示文件的字节数
wc -L access.log
-L得出最长的行长度
wc -w access.log
-w 查看文件包含多少单词
重复行
uniq
sort uniqfile| uniq -c
-c 用来在每一行前面加上该行出现的次数
sort uniqfile | uniq -c -u
-u 只会显示出现一次的行
sort uniqfile | uniq -c -d
-d 只会显示重复出现的行
字符串查找
grep
> grep earyant access.log earyant 为指定的查找串 > grep -c earyant access.log -c 可以显示查找到的行数 > grep 'G.\*T' access.log 支持正则表达式
文件查找
find
find /home/earyant -name access.log
在/home/earyant 目录下查找文件名为access.log的文件
find /home/earyant -name “*.txt”
find . -print
打印当前目录所有文件
whereis
whereis java
- which
which java
表达式求值
- expr
expr 10 * 3
expr 10 % 3
expr index “earyant.github.io” earyant
压缩
tar
tar -cf aaa.tar tmp1 tmp2
将当前目录下的tmp1和tmp2目录打包成aaa.tar -c 表示生成新包 -f 指定包名称
tar -tf aaa.tar
-t 能够列出包中文件的名称
tar -xf aaa.tar
-x 将打包文件解压
url 访问工具
curl
curl www.baidu.com
curl -i www.baidu.com
-i 返回带header的文档
curl -I www.baidu.com
-I 只返回页面的header信息
查看请求访问量
cat access.log | cut -f1 -d “ “ | sort | uniq -c | sort -k 1 -n -r | head -10
访问量排名前10的ip地址
cat access.log | cut -f4 -d “ “ | sort | uniq -c | sort -k 1 -n -r | head -10
页面访问量排名前10的url
查看最耗时的页面
cat access.log | sort -k 2 -n -r |head -10
统计404请求的占比
1 | export total_line = `wc -l access.log | cut -f1 -d " "` && export not_found_line = `awk '$6=='404'{print $6}' access.log | wc -l` && expr $ not_found_line \*100 / $total_line |
Guava 1.1基本工具
本文字数: 1.6k 阅读时长 ≈ 1 分钟
1.1-使用和避免null
map允许null作为键,但只能有一个。
concurrentHashMap不允许null作为键。
Optional
1 | Optional<Integer> possible = Optional.of(5); |
静态创建方法
- of
- ofNullable
- empty
实例方法
- isPresent
- get
- or (jdk中是orElse)
- orNull
- asSet
意义:
使用Optional除了赋予null语义,增加了可读性,最大的优点在于它是一种傻瓜式的防护。Optional迫使你积极思考引用缺失的情况,因为你必须显式地从Optional获取引用。直接使用null很容易让人忘掉某些情形,尽管FindBugs可以帮助查找null相关的问题,但是我们还是认为它并不能准确地定位问题根源。
如同输入参数,方法的返回值也可能是null。和其他人一样,你绝对很可能会忘记别人写的方法method(a,b)会返回一个null,就好像当你实现method(a,b)时,也很可能忘记输入参数a可以为null。将方法的返回类型指定为Optional,也可以迫使调用者思考返回的引用缺失的情形。
使用方式:
- 错误的使用方式:
1
2
3
4
5
6Optional<User> user = Optional.ofNullable(user);
if (user.isPresent()) {
int sex = user.getSex();
// 链式调用,最容易出现空指针
int age = user.getParent().getParent().getParent().getAge();
} - 正确的使用方式
1
2
3Optional<User> user = Optional.ofNullable(user);
int sex = user.map(User::getSex).orElse(0);
int age = user.map(User::getParent).map(User::getParent).map(User::getParent).map(User::getAge).orElse(0);
其他处理null的便利方法
- Objects.firstNonNull(T, T)
- Objects还有其它一些方法专门处理null或空字符串:emptyToNull(String),nullToEmpty(String),isNullOrEmpty(String)。
1.2-前置条件 Preconditions
— | — | — |
---|---|---|
方法声明(不包括额外参数) | 描述 | 检查失败时抛出的异常 |
checkArgument(boolean) | 检查boolean是否为true,用来检查传递给方法的参数。 | IllegalArgumentException |
checkNotNull(T) | 检查value是否为null,该方法直接返回value,因此可以内嵌使用checkNotNull。 | NullPointerException |
checkState(boolean) | 用来检查对象的某些状态。 | IllegalStateException |
checkElementIndex(int index, int size) | 检查index作为索引值对某个列表、字符串或数组是否有效 | IndexOutOfBoundsException |
checkPositionIndex(int index, int size) | 检查index作为位置值对某个列表、字符串或数组是否有效。 | IndexOutOfBoundsException |
checkPositionIndexes(int start, int end, int size) | 检查[start, end]表示的位置范围对某个列表、字符串或数组是否有效* | IndexOutOfBoundsException |
JDK1.5-JDK1.8各个新特性
本文字数: 4 阅读时长 ≈ 1 分钟
java内存模型
本文字数: 2 阅读时长 ≈ 1 分钟
情深不寿
如果我孑身一人是个赛车手
无牵无挂,无畏无惧
即使受伤、死亡
也会为我爱的事倾尽所有
如果我生在乱世是个将军
交出我爱的人换取一时和平
不要和我讲大义
提枪上马,马革裹尸不休
爱吃西瓜
最甜的是西瓜中间的那口
可我连籽都吃掉
我爱的东西本来就不多
爱就爱它的所有
docker简单结合elk、logstash
本文字数: 729 阅读时长 ≈ 1 分钟
本文记录docker搭建elk,并简单结合logstash日志输出
filebeat
docker pull docker.elastic.co/beats/filebeat:6.2.1
- filebeat.yml
enabled要改为true,filebeat默认为false1
2
3
4
5
6
7
8filebeat.prospectors:
- type: log
enabled: true
paths:
- D:\workspace\baidu\baiyi\baidu\dsp\dsp-main-server\log\*.log
output:
logstash:
hosts: ["192.168.99.100:5044"]docker run -it —name filebeat -v /data/filebeat.yml::/usr/share/filebeat/filebeat.yml
logstash
改写/opt/logstash/logstash/config/logstash.yml文件
- logstash.yml
1 | input{ |