有段时间没有跟学弟学妹们互动了,因为最近这段时间实在是太忙了,因为快临近双十一嘛!
言归正传啊,上次有学妹跟我聊,刚去公司不熟悉环境,Linux系统不熟悉,很多命令不知道怎么用,外加上公司里面查询日志还是使用跳板机的方式,所以特别被动。今天就跟大家聊聊一些简单实用的Linux命令来面对一些工作中遇到问题。
什么是Linux?
Linux全称GNU/Linux,是一种免费使用和自由传播(开源)的UNIX操作系统,安装在我们我们的计算机硬件上,用来管理计算机的硬件和软件资源管理等。
当然也并不只是因为免费和开源导致Linux为啥这么火的,相比于widows系统它还是有很多优点的:
Linux相比较于widows系统他更注重安全性,比如说在Linux目录的下的文件都有一个权限的控制,不同的用户访问的权限能有不同的控制权限,所以它的安全性更好一点
相比较于widows系统,Linux的稳定性更好,很少会出现系统崩溃的情况出现,因为权限控制到位了,很多核心应用文件没有权限是不能进行操作的,还有很多配置更改都不需要去重启机器,不会影响到相关的服务程序。
Linux还有很多其他的一些特点比如说灵活性,因为开源嘛,还有对硬件没啥要求等等,所以现在很多的公司都是使用Linux系统来作为服务器。
而我们在服务器终端输入的命令通过命令解析器(常见的有 shell,)处理完之后才真正的被运行。
今天主要是从三个方面跟学妹聊Linux,其实就是一些我们工作中比较实用的命令
- Linux的基础命令
- Java中的服务器排查问题命令
- 扩展Arthas中的常见用法(号称 Java诊断神器)
Linux的基础命令
一些简单的常见的我就不跟大家一一列举出来了,这个直接百度一下就全部都有了
文件相关命令
ls :显示当前目录下所有的文件
ls -a :列出所有文件,包括以 "." 开头的隐含文件。
ll :显示当前文件或目录的详细信息,含有时间、读写权限、大小、时间等信息,等于是 ls -l 命令
du :用于显示目录或文件的大小。一般用来查看文件的大小,比如说看一些dump的日志的文件的大小
du -sh * :查询当前目录下所有的文件的大小以K,M,G为单位,提高信息的可读性。
- 场景:查看服务器中一个文件(比如日志)大小,在删除磁盘文件的时候能有一个对比,那个文件占用磁盘最大
cat :输出当前文件内容。
- 场景:一般就是用来查看当前文件的内容,比如说要看下服务器的启动service.sh脚本文件中的内容(cat service.sh)
- 扩展:cat -n fileName 输出文件内容并且在前面加上行号。
- 扩展:cat -b fileName 输出文件内容并且在前面加上行号,与上面的不同是会过滤空白行。
- 扩展:cat -n textfile1 > textfile2 把 textfile1 的文档内容加上行号后输入 textfile2 这个文档里。
more :跟cat差不多,但是有一个优点就是展示出来的是按照页的形式出来,可以接着按space空格键向下翻页
- 扩展:more -num 一次显示行数。
- 扩展:more +num 从第num行开始显示。
chmod :修改当前用户对文件的权限
- r=4,w=2,x=1,所以想要rxw 读写和可执行权限,那就是4+2+1=7,而一个位数表示一个角色,chmod a=rwx txt1.txt就可以理解为就是 chmod 777 txt1.txt
- u 表示该文件的拥有者,g 表示与该文件的拥有者属于同一个群体(group)者,o 表示其他以外的人,a 表示这三者皆是
- + 表示增加权限、- 表示取消权限、= 表示唯一设定权限
- r 表示可读取,w 表示可写入,x 表示可执行
- 场景:chmod这个命令实用比较广泛,但是说白了就是一点更改文件权限,但是权限这个东西怎么加,是加所有用户还是其他?是加读写还是去除读写?这个就需要理解 u、g、o、a、+、-、=、r、w、x等含义
- 扩展:chmod ugo+r txt1.txt 或者 chmod a+r txt1.txt 设置txt1.txt 对所有的用户角色可读
- 扩展:chmod 777 file ,chmod也可以用数字来代表权限问题,
diff :用于比较文件的差异。
- 扩展:diff log1.log log2.log -y -W 50并排输出两个文件的不同。
grep :用于查找文件里符合条件的字符串,这个是最常见的也是日常查询文件最常用的。
- $grep 2021-10-27T20:17:20.519+0800 gc.log | wc -l
- 1
- $grep 2021-10-27T21 gc.log | grep 25:33
- 2021-10-27T21:25:33.413+0800: 797616.955: [GC (Allocation Failure) 2021-10-27T21:25:33.414+0800: 797616.955: [ParNew: 848318K->18793K(943744K), 0.0263809 secs] 1283786K->454263K(1992320K), 0.0270603 secs] [Times: user=0.09 sys=0.00, real=0.03 secs]
- 扩展:grep "aaa" log.log -A 10 ,除了显示符合搜索条件的那一列之外,并显示该行之后的10行内容。wc
- 扩展:grep "aaa" log.log -B 10 ,除了显示符合搜索条件的那一列之外,并显示该行之前的10行内容。
- 扩展:grep "aaa" log.log | grep "bb" -A 10,同时搜索满足条件以上两个条件的结果,并向下在打印剩下的10行。
- 扩展:grep "aaa" log.log | wc -l,统计满足条件的的次数
scp : 命令用于 Linux 之间复制文件和目录。可以用来作为下载文件到本地的一种方式。scp 是 secure copy 的缩写, scp 是 linux 系统下基于 ssh 登陆进行安全的远程文件拷贝命令。
- 打开本地系统服务 文件 远程登入 允许访问 所有用户
- 输入:scp heap.hprof aobing@172.19.36.87:/Users/aobing/Downloads
- 输入本机电脑登入密码即可,就能显示当前在下载的进度了
- 扩展:举一个用法的例子,假设用我自己当前电脑作为演示,怎么去把我们跳板机中的dump文件下载到我们本地,以便于我们自己来分析堆栈呢?
- 这个是比较常用的方法,可以有其他的用法,就因个人而已吧
mkdir :用于创建目录。这个是最简单的了。
- 扩展:mkdir aaaa 创建一个aaaa文件
kill :删除执行中的程序或工作,这个需要慎重使用,我们可以一般在我们的电脑卡死,或者我们本地启动tomcat端口被占用了,但是我们又没有找到,可以ps查一下进程ID,然后kill一下
- 扩展:kill 14269,杀死14269这个进程
- 扩展:kill -KILL 14269,强制杀死14269这个进程
- 扩展:kill -9 14269,彻底杀死14269这个进程
rm :用于删除一个文件或者目录。在使用这个命令之前需要注意,不要随便执行这个命令,文件一旦通过rm命令删除,则无法恢复所以可能有时候不小心删除某些文件,第二天新闻就出来“杭州某公司丙某因为执行时rm -rf命令,导致服务器或者数据库 数据丢失 造成严重损失”
- $rm gc.log.20210506151038
- rm: remove regular file ‘gc.log.20210506151038’? y
- 扩展:rm gc.log.20210506151038 ,删除 gc.log.20210506151038 文件?会跳出一个确定提示,输入 y,则是删除
- 扩展:rm -f gc.log.20210506151038,不会产生确认删除提示,直接删除文件
- 扩展:rm -rf gc.log.20210506151038,不会产生确认删除提示,直接删除文件,并且会把当前目录下的所有文件一并删除,非常的暴力。
gzip :用于压缩文件。文件经它压缩过后,其名称后面会多出".gz"的扩展名。当服务器某个文件过大时,你下载非常的慢,所以考虑一下压缩之后再下载。
- 扩展:gzip gc.log.20210506151038 ,压缩一下文件gc.log.20210506151038,压缩之后会生成一个文件gc.log.20210506151038.gz,这个比较简单,压缩完可以使用上面的 ll 或者 du 等相关命令再查看下文件的大小。
- 扩展:gzip -<压缩效率> gc.log.20210506151038 , 压缩效率是一个介于1-9的数值,预设值为"6",指定愈大的数值,压缩效率就会愈高,控制压缩比例。
ps :(全拼:process status)用于显示当前进程的状态,主要是用来查询当前进程的状态,比如说需要查询一下当前tomcat的相关信息,或者说服务器配置的tomcat的一些启动参数,都是可以看到。
- $ps -ef | grep tomcat
- www 383 304 0 00:02 pts/0 00:00:00 grep --color=auto tomcat
- www 5579 1 8 Oct22 ? 10:36:09 /opt/vdian/java/bin/java -Djava.util.logging.config.file=/home/www/item-sell/.server/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -server -Xms5g -Xmx5g -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m -Xmn2g -XX:MaxDirectMemorySize=512m -XX:SurvivorRatio=8
- 扩展:ps -ef | grep 进程关键字,查询某个关键字的进程,如下所示,能显示很多信息。我这里没有复制全,自己可以进公司的服务试一下,不会有问题的。
- 扩展:ps -A,列出所有的进程
- 扩展:ps -aux,显示所有包含其他使用者的行程
- 等等还有很多很多,我就举出常用的,一一列举大家不常用也就没有什么意思。
pwd :用于显示工作目录,这个命令就很简单了, 没有什么特殊的参数啥的,就是显示当前目录地址。
- $pwd
- /home/www
- 扩展:pwd,跟简单,后面不需再加什么参数,显示一下目录,方便下我们复制文件的目录地址。
source :这个命令一般就是和**点(.)**是一样的效果,就是修改了某个文件不用重启,而可以立马生效
- 扩展:source fileName等于. fileName是一个效果。使改动的文件立即生效
tail :用于查看文件的内容。通常比如说我们需要查看正在变动的日志文件,那就可以用这个命令了。
- 扩展:tail -f filename,会把 filename 文件里的最尾部的内容显示出来,并且不断刷新,只要 filename 更新就可以看到最新的文件内容。
- 扩展:tail -20f filename,会把 filename 文件里的最后的20行内容显示出来,并且不断刷新。
- 扩展:tail -c 20 filename,显示文件 filename 的最后 20 个字符。
- 扩展:tail -n +20 filename,显示文件 filename 的内容,从第 20 行至文件末尾。
以上就是在Linux中我们工作中比较常用的一些命令,以及它们的一些扩展,当然,这个并不是全部的,我也只是列出了冰山一角。如果还是没有满足你们的日常工作可能就需要你们自己的再去查查资料,看看书了。
Java中的常见排查问题命令
在工作中都会多少都会接触到一些服务器调优,或者说一些线上问题排查,这是在面试过程中,面试官比较喜欢问的一个问题,也是为了考察面试者的思考能力以及动手能力和基础是否扎实。都说是面试造飞机,进去拧螺丝。很多时候问题都轮不到你来处理,但是你还是得会。
之前也有很多学弟学妹来给我留言怎么去排查一些线上服务器问题,比如说某个时间 dubbo线程池满,内存告警,以及OOM等。
所以这里主要也就跟学弟学妹从三个方面负载、cpu、内存 这三个方面去聊聊,怎么通过一些命令去看这些东西。
负载
负载是对当前CPU的工作量的一个度量,通常负载越低,说明机器工作轻松,反之则越累,高负载的情况下就可能会出现机器无法处理其他的业务请求了。
查看负载的命令有很多,top、uptime 等都可以查看
- $uptime
- 01:13:53 up 319 days, 14:05, 1 user, load average: 0.39, 0.34, 0.39
从这个信息看,我们要关注的 是后面的 load average 显示的信息
- load average:0.39, 0.34, 0.39 这三个数字的意思分别是1分钟、5分钟、15分钟内系统的平均负荷
- user:1 user,当前一个用户登入
前面显示的信息就是服务器启动到现在已经有多长时间了。
top 命令是比较常见的,也是最常用的,因为他显示的信息也是最全的。
- $top
- top - 01:19:56 up 319 days, 14:11, 1 user, load average: 0.13, 0.25, 0.35
- Tasks: 145 total, 1 running, 144 sleeping, 0 stopped, 0 zombie
- %Cpu(s): 2.8 us, 0.9 sy, 0.3 ni, 95.6 id, 0.1 wa, 0.0 hi, 0.2 si, 0.2 st
- KiB Mem : 8173324 total, 142188 free, 5861548 used, 2169588 buff/cache
- KiB Swap: 0 total, 0 free, 0 used. 1634952 avail Mem
- PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
- 7704 www 20 0 9714024 4.824g 5932 S 27.6 61.9 3717:34 java
- 2150 root 30 10 785008 58672 35804 S 1.7 0.7 3254:22 polaris-agent
- 16043 www 20 0 3800732 402604 3788 S 0.3 4.9 603:29.85 java
- 1 root 20 0 43536 3396 1948 S 0.0 0.0 56:12.32 systemd
这里可以看到除了显示平均负载的情况下还能显示 CPU相关信息。还有每个进程占用的资源情况。
针对负载的问题,我们怎么能确定负载当前是高还是低?
一般来说只要负载超过0.7可能就表示当前负载有点高了,需要排查一下,这个是针对单核CPU来说的,如果是多核CPU来说,我们就是CPU核数乘以0.7来计算的。
在top显示的进程信息的时候,我们可能看到当前进程中 7704这个进程 占用CPU最高,而且是我们的Java进程
假设现在是CPU被这个进程占用百分之90,那我们就可以重点排查一下这个进程到底在做什么导致CPU占用这么高
- $top -Hp 7704
- top - 01:33:05 up 319 days, 14:24, 1 user, load average: 0.12, 0.23, 0.31
- Threads: 651 total, 5 running, 646 sleeping, 0 stopped, 0 zombie
- %Cpu(s): 2.1 us, 0.8 sy, 0.3 ni, 96.4 id, 0.1 wa, 0.0 hi, 0.3 si, 0.1 st
- KiB Mem : 8173324 total, 143612 free, 5862648 used, 2167064 buff/cache
- KiB Swap: 0 total, 0 free, 0 used. 1633376 avail Mem
- PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
- 9046 www 20 0 9714024 4.824g 5932 S 4.6 61.9 13:12.99 java
- 8415 www 20 0 9714024 4.824g 5932 R 2.6 61.9 442:19.10 java
- 8418 www 20 0 9714024 4.824g 5932 R 2.6 61.9 424:18.67 java
top -Hp 是查看当前进程中的所有的线程情况,同样的可以看到 9046 这个线程占用比较高,那么我们再接着分析这个线程在处理什么逻辑就可以了。
- $printf %s 9046
- 2356
使用printf命令查看这个线程的16进制
最后使用jstack命令查看当前线程正在执行的什么方法
- $jstack 7704 | grep -A 10 2356
- "DubboServerHandler-10.33.130.247:2201-thread-154" #867 daemon prio=5 os_prio=0 tid=0x00007f4ef005a800 nid=0x2356 waiting on condition [0x00007f4ec1acf000]
- java.lang.Thread.State: WAITING (parking)
- at sun.misc.Unsafe.park(Native Method)
- - parking to wait for <0x0000000708513d48> (a java.util.concurrent.SynchronousQueue$TransferStack)
- at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
- at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:458)
- at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)
- at java.util.concurrent.SynchronousQueue.take(SynchronousQueue.java:924)
- at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
- at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
- at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
从这里就能大致做一个分析了,但是这个不一定都能确定出来问题,但是能给我展示出一些有用的信息。具体的还需要我们再去看下这里执行了什么方法。
再或者我们直接使用 jmap 来dump内存。
CPU
在看CPU信息的时候主要关注的点就是CPU的使用率。
在上面使用top能查看CPU的使用情况之后,还有一个vmstat命令,这个命令有一个好处可以看到内存使用,虚拟内存还有IO等信息。
- $vmstat
- procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
- r b swpd free buff cache si so bi bo in cs us sy id wa st
- 0 0 0 172572 0 2133780 0 0 1 51 0 0 4 1 95 0 0
- us:用户进程执行时间百分比(如果当前值比较高,说明用户进程消耗高)
- sy:内核系统进程执行时间百分比(如果系统比较高,那么你可以找运维了)
- id:空闲时间百分比
- wa:IO等待时间百分比(如果IO时间长,那说明机器在大量的处理磁盘的读写操作,这个也是关注的重点,可能写日志啊等都有可能)
- st:虚拟 CPU 等待实际 CPU 的时间的百分比
所以触发CPU高的场景也有很多,这个CPU高可能只是一个 “果的关系”,具体的“因”是啥还需要在进步排查,比如说再用top,按上面的思路再看下。
内存
内存是保证我们程序能正常运行的关键,这个也是需要我们查看的一个关键指标数据。
查看内存的命令除了上面的top之外还有一个free来查看内存数据。细心的人应该发现了top命令真的展示信息最全了。当然我们还是主要分析一下这个命令展示的数据,以及怎么分析这些数据。
- $free
- total used free shared buff/cache available
- Mem: 8173324 5870868 126448 401812 2176008 1625028
- Swap: 0 0 0
Mem行,顾名思义也就是展示内存的使用情况
- total:表示物理内存总大小
- used:已经被使用的物理内存和交换空间
- free:表示未被分配的内存
- shared:共享使用的物理内存大小
- buff/cache buffer 和 cache 使用的物理内存大小
- available:当前剩余实际可用内存(还可以被应用程序使用的物理内存大小)
Swap:这个被称之为交换区,当系统内存不够使用时,释放磁盘内存,来保证当前运行的程序能正常使用(Linux会将一些不常访问的数据保存在交换区,但是目前一般不会配置)。
- Total:Swap内存总大小
- Used:已分配的Swap大小
- Free:未被分配的内存
所以在查看内存的时候我们还是不能不能确定这个因果关系,在出现问题的时候,如果我们没有一个很好的思路,就先看看这三个指标,可以通过一些排除法来给我们一些思考。
但是现在我们最常用的基本都是看top 一下看看各个指标,如果确定是Java进程的问题,很多时候都会去dump一下内存,来分析一下对象信息。如果有很多大对象,一直被引用那就具体看代码了。一般的问题大部分都是因为我们的代码引起的。
Arthas
说到dump内存,常见的可能就是使用jmap 命令来处理,但是这里跟大家分享一个新的阿里开源的工具Arthas。
Arthas 是Alibaba开源的Java诊断工具,深受开发者喜爱。在线排查问题,无需重启;动态跟踪Java代码;实时监控JVM状态。
我个人觉得也确实是蛮好用的。官方文档:https://arthas.aliyun.com/doc/arthas-tutorials.html?language=cn
首先就是先安装一下
- $curl -O https://arthas.aliyun.com/arthas-boot.jar
- % Total % Received % Xferd Average Speed Time Time Time Current
- Dload Upload Total Spent Left Speed
- 100 138k 100 138k 0 0 420k 0 --:--:-- --:--:-- --:--:-- 421k
启动
- $java -jar arthas-boot.jar
- [INFO] arthas-boot version: 3.5.4
- [INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
- * [1]: 20851 /home/www/xxxxx/xxxx.14_75b3f783befda28c22c6ce8b48d7f41b_prod.jar
- [2]: 6152 com.xxxx.xxxx.xxxx.main.Main
这里看到会有两个应用但是我们需要进入Java应用,所以直接按2,进入。
因此如果需要dump堆栈内存只要一个命令就可以了
dump到指定文件
- heapdump /tmp/dump.hprof
只dump live对象
- heapdump --live /tmp/dump.hprof
在dump堆栈的时候是会触发fullGC的这个需要注意一下,一般针对这有问题的机器,可以先把这个机器offline掉,这样流量进不来,保证平台先“止血“。
在获取到堆栈信息之后那就是分析堆栈了,可以MAT、Jprofiler等,但是还有一个简单的轻小的gceasy也可以去分析一个堆栈信息。
还有一个我们比较常用的功能就是分析我们方法的耗时问题。
假设现在我们有个方法,里面有很多子方法,包含很多rpc掉用,以及很多很多的业务逻辑在里面,那我们怎么去获取每个子方法的耗时呢?
针对相信上面的问题,很多人都会想到先用System.currentTimeMillis()来获取当前时间,然后每执行一个方法在减去开始的时间以此来得到一个时间差,再用日志打印出来。这样虽然是可行的,但是非常的麻烦。Arthas里面有一个trace命令就能帮我处理这个问题。
- [arthas@6152]$ trace com.xxxx.xxx.xxx.service.ItemSnapshotService saveFullSnapshot
- Press Q or Ctrl+C to abort.
- Affect(class count: 1 , method count: 1) cost in 231 ms, listenerId: 3
- `---ts=2021-10-28 02:50:23;thread_name=ConsumeMessageThread_4;id=3c2;is_daemon=false;priority=5;TCCL=sun.misc.Launcher$AppClassLoader@18b4aac2
- `---[3.939696ms] com.xxx.xx.xx.service.ItemSnapshotService:saveFullSnapshot()
- +---[0.047704ms] com.xxx.xx.xx.service.ItemSnapshotService:$jacocoInit()
- +---[0.014779ms] com.xx.xx.xx.xx.snapshot.ItemSnapShot:getItemId() #304
- +---[0.008545ms] com.xxx.xxx.xx.x.snapshot.ItemSnapShot:getOperateTime() #305
- +---[0.306668ms] com.xx.xxx.xx.service.ItemSnapshotService:buildRowKey() #306
- +---[0.006373ms] com.xxx.xx.xxx.domain.snapshot.ItemSnapShot:getAfter() #307
- +---[0.004874ms] com.xx.xx.xx.domain.snapshot.ItemSnapShot:getBefore() #307
- +---[0.058562ms]
展示结果如上所示,还有能做过滤啊,统计次数啊等等一些功能。
Arthas它的功能还有很多很多啊,我也一下子说不完,感兴趣的同学可以去看看我贴的那个官方文档。之所以跟大家聊这个是我觉得确实挺好用的,在我们的工作中能起到一个很好的帮助。
总结
这次跟大家分享的都是我个人感觉在工作中比较实用的一些常见命令以及工具,以及在工作中会经常遇到的一些问题。这也是在面试的过程中您能和面试官聊的东西。只有当别人不知道而你知道那你就走在别人的前面,不是故意要卷,而是当前互联网就是一个卷的时代了。
本次要跟学弟学妹聊的一些命令就到到这里了,虽然扩展了很多其他的东西,但是我感觉还是比较有用的吧!!!