【原】踩坑启示录其零壹

【引言】很久之前就想搞这么一个知识库,搜集日常工作中常遇到的一些坑,想来也是因为自己有些懒惰,竟至于拖到今日方才成行;本章为此踩坑启示录系列的第1篇,力求开个好头。


说在前面

  工作多年,技术岗是一个常学常新的岗位,即使是同一个东西,版本的不断升级也要求我们必须要时刻保持着一颗好好学习天天向上的精神去追逐。
  当然,新的东西往往都是我们未知的,不熟悉的;既然不熟悉,那难免多多少少会遇到一些坑,如今虽内有百度外有谷歌,但总的来讲查到的还是别人的,可能解决了这次,还有下次,不总结的知识永远也不可能为我们所用的。
  最近偶尔翻阅今日头条,总有个主题冒出来,大致是说《不要假装很努力,不会总结都是白搭》,具体的内容我也草草扫过几眼,其实跟我个人的感悟雷同;这么些年,我们学过的东西不少,但我们存下来的东西有多少呢?我们不能把自己当做管道,我们要试着让自己变成缓存,甚至更高的要求一些让自己变成一个数据库,我们要试着让经过我们的知识持久化。
  当然,技术有难易,一如不同的排序算法还有不同的复杂度呢;个人的悟性也有区别,一如我们机械硬盘和SSD的存储效率也是不在一个级别的;所以各人还是要摸索出适合自己的法门,一如因材施教,教自己也是一门学问。
  80年代生的我们,想必都对这句歌词记忆犹新吧:“看时光飞驰我祈祷明天,每个小小梦想能够漫漫实现!”;今天的祈祷,明天的现实,并不是空穴来风一蹴而就的,需要的是日积月累的历练和沉淀的。
  前面说了很多废话,到现在还没有提到这个系列的主题,本系列个人的愿望是打造成自己的一个踩坑知识库,很多坑总会不止一次的遇到,所以想做起这么一个系列,每个章节围绕一个主题坑的解决来写,不限篇幅,也为将来再次遇到的时候有个查阅的地方。
  最后,以开篇图古人之词与同仁共勉,路漫漫其修远兮,吾辈尚任重而道远。

Maven编译时找不到rt.jar里的类

【问题缘起】
  在使用Maven编译tools-common包的时候,发现某个类始终报找不到,经过查询,发现该类属于rt.jar,如何解决这个问题呢?

【解决方法】
  在pom.xml的maven编译插件定义中,加入了compilerArguments定义引入rt.jar(另需要在pom头部定义java.home为当前主机的java主目录方可编译通过)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
<encoding>utf8</encoding>
<compilerArguments>
<verbose />
<bootclasspath>${java.home}\lib\rt.jar;${java.home}\lib\jce.jar
</bootclasspath>
</compilerArguments>
</configuration>
</plugin>

JDK的Date比实际时间差8小时

【问题缘起】
  在记录某些数据更新时间时,使用JDK的new Date()方法,发现在未设置时间时,记录的时间默认比当前时间要推迟8小时(推测基本上是因为标准时间和东八区的差异引起的),那要如何解决呢?

【解决方法】
  在系统上执行以下命令: sudo dpkg-reconfigure tzdata

The last packet sent successfully to the server was 0 milliseconds ago

【问题缘起】
  今天在使用JDBC操作mysql时遇到下面的异常信息:

1
2
3
4
5
6
7
8
9
The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received any packets from the server. 
at com.tomymap.galaxy.virgo.util.DbService.getConnection(DbService.java:66)
at com.tomymap.galaxy.virgo.util.DbService.getConnection(DbService.java:46)
at com.tomymap.galaxy.virgo.dao.PNNDao.getConnection(PNNDao.java:51)
at com.tomymap.galaxy.virgo.dao.DaoBase.executeUpdate(DaoBase.java:69)
at com.tomymap.galaxy.virgo.dao.PNNDao.updatePNNRelation(PNNDao.java:161)
at com.tomymap.galaxy.virgo.pnn.PyramidNeuralNetwork.buildPNNRelations(PyramidNeuralNetwork.java:400)
at com.tomymap.galaxy.virgo.pnn.PyramidNeuralNetwork.incrementalGenPNN(PyramidNeuralNetwork.java:144)
at com.tomymap.galaxy.virgo.pnn.PyramidNeuralNetwork.main(PyramidNeuralNetwork.java:410)

【解决方法】
(1)使用JDBC URL中使用autoReconnect属性,url添加&autoReconnect=true&failOverReadOnly=false&maxReconnects=10
(2) 修改MySQL的参数. /etc/my.cnf 添加如下配置后重启服务service mysql restart

1
2
3
[mysqld]  
wait_timeout=31536000
interactive_timeout=31536000

【补充说明】
(1)大量并发访问情况下,mysql connection连接有可能失效
(2)长时间不妨问,connection会失效

Maven编译插件如何配置?

【问题缘起】
  需要使用Maven编译出jar、source、jdoc三个包,该如何配置pom文件?

【解决方法】
  在pom.xml的尾部添加如下部分配置即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArguments>
<verbose />
<bootclasspath>${java.home}/lib/rt.jar;${java.home}/lib/jce.jar</bootclasspath>
</compilerArguments>
</configuration>
</plugin>
<plugin>
<artifactId>maven-source-plugin</artifactId>
<version>3.0.1</version>
<configuration>
<attach>true</attach>
</configuration>
<executions>
<execution>
<phase>compile</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9</version>
<configuration>
<charset>UTF-8</charset>
<docencoding>UTF-8</docencoding>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

Tomcat启动时卡在“INFO Deploying web application directory ”

【问题缘起】
  Tomcat启动时卡在“INFO: Deploying web application directory ”

【解决方法】
  在 $JAVA_HOME/jre/lib/security/java.security内,将securerandom.source的内容改为file:/dev/./urandom

【补充说明】
  原来linux或者部分unix系统提供随机数设备是/dev/random 和/dev/urandom ,两个有区别,urandom安全性没有random高,但random需要时间间隔生成随机数。可能在生成随机数的时候卡住了,导致tomcat启动不了,在服务器启动时也可以加上参数 -Djava.security.egd=file:/dev/./urandom

怎么通过Java临时修改环境变量?

【问题缘起】
  因某些特殊场景需要,需在程序中临时修改环境变量,如何通过Java来实现呢?

【解决方法】

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/* 
* 文件名:EnviromentChangeUtil.java
* 描述:环境变量修改
* 创建人:chenglin
* 创建时间:2017-3-10
*/
package com.demo;

import java.lang.reflect.Field;
import java.util.Collections;
import java.util.Map;

/**
* 临时修改系统环境变量(仅对内存生效)
* @author chenglin
* @version 1.0
*
* <br/>
* <br/>修订人 修订时间 描述信息
* <br/>-----------------------------------------------------
* <br/>chenglin 2017-3-10 初始创建
*/

public class EnviromentChangeUtil {

/**
* 临时修改系统环境变量(仅对内存生效)
* @param envMap
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static void setEnv(Map<String, String> envMap) {
try {
Class<?> processEnvironmentClass = Class
.forName("java.lang.ProcessEnvironment");
Field theEnvironmentField = processEnvironmentClass
.getDeclaredField("theEnvironment");
theEnvironmentField.setAccessible(true);
Map<String, String> env = (Map<String, String>) theEnvironmentField
.get(null);
env.putAll(envMap);
Field theCaseInsensitiveEnvironmentField = processEnvironmentClass
.getDeclaredField("theCaseInsensitiveEnvironment");
theCaseInsensitiveEnvironmentField.setAccessible(true);
Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField
.get(null);
cienv.putAll(envMap);
} catch (NoSuchFieldException e) {
try {
Class[] classes = Collections.class.getDeclaredClasses();
Map<String, String> env = System.getenv();
for (Class cl : classes) {
if ("java.util.Collections$UnmodifiableMap".equals(cl
.getName())) {
Field field = cl.getDeclaredField("m");
field.setAccessible(true);
Object obj = field.get(env);
Map<String, String> map = (Map<String, String>) obj;
map.clear();
map.putAll(envMap);
}
}
} catch (Exception e2) {
e2.printStackTrace();
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
}

Tomcat 8.5+版本文件上传后无权限访问的问题

【问题缘起】
  之前在tomcat 7下文件上传后访问一直没问题,现在tomcat版本升到8.5,在测试文件http上传时,发现所传文件无法通过nginx访问了。PS:tomcat通过root用户来启动。(Tomcat默认写的文件权限是740,实际访问需要的是755)

【解决方法】
  在catalina.sh文件的大约第270行左右有下面一段配置,这里的UMASK就是用于管理文件访问权限的(实际权限为:777-UMASK);所以将其改为UMASK=”0022”并重启tomcat 8.5后,文件上传后访问恢复正常。

1
2
3
4
5
6
# UMASK           (Optional) Override Tomcat's default UMASK of 0027
# Set UMASK unless it has been overridden
if [ -z "$UMASK" ]; then
UMASK="0027"
fi
umask $UMASK

【补充说明】
  英文文档也是在定位了tomcat 8.5问题后搜索关键词tomcat8.5 umask后在tomcat官网文档及相关英文论坛里发现了踪迹。
  参考文档1: http://tomcat.apache.org/tomcat-8.5-doc/changelog.html

1
2
3
4
5
6
Tomcat 8.5.0 (markt)
General
Update: Remove support for Comet. (markt)
Update: Tighten up the default file permissions for the .tar.gz distribution so no files or directories are world readable by default.
Configure Tomcat to run with a default umask of 0027 which may be overridden by setting UMASK in setenv.sh. (markt)
Update: Remove native code (Windows Service Wrapper, APR/native connector) support for Windows Itanium. (markt)

  参考文档2:http://tomcat.apache.org/tomcat-8.5-doc/security-howto.html

1
2
3
4
5
6
7
8
9
Non-Tomcat settings
Tomcat configuration should not be the only line of defense. The other components in the system (operating system, network, database, etc.) should also be secured.

Tomcat should not be run under the root user. Create a dedicated user for the Tomcat process and provide that user with the minimum necessary permissions for the operating system.
For example, it should not be possible to log on remotely using the Tomcat user.

File permissions should also be suitably restricted. In the .tar.gz distribution, files and directories are not world readable and the group does not have write access.
On Unix like operating systems, Tomcat runs with a default umask of 0027 to maintain these permissions for files created while Tomcat is running (e.g. log files, expanded WARs, etc.).
...

-bash: fork: Cannot allocate memory

【问题缘起】
  在阿里云上有一台服务器(4vCPU 32G),突然有同学反映连不上去了,服务也用不了了(幸好是测试环境),强登上去之后发现各种报 Cannot allocate memory,但是硬执行了下free查看,内存还丰富的很,那这是为啥呢?

1
2
3
4
5
6
[root@smart0002 ~]# free -m
total used free shared buffers cached
Mem: 32241 23690 8550 0 16 112
-/+ buffers/cache: 23561 8679
Swap: 0 0 0
[root@smart0002 ~]#

【解决方法】
  经过度娘的协助,最终确认是进程数满了导致的,于是修改了一下kernel.pid_max内核参数,顺利解决此问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[root@smart0002 ~]# sysctl kernel.pid_max
kernel.pid_max = 32768
[root@smart0002 ~]# ps -eLf | wc -l
-bash: fork: Cannot allocate memory
[root@smart0002 ~]# ps -eLf | wc -l
32545
[root@smart0002 ~]# echo "kernel.pid_max=1000000 " >> /etc/sysctl.conf
[root@smart0002 ~]# sysctl -p
net.ipv4.ip_forward = 0
net.ipv4.conf.default.accept_source_route = 0
kernel.core_uses_pid = 1
kernel.msgmnb = 65536
kernel.msgmax = 65536
kernel.shmmax = 68719476736
kernel.shmall = 4294967296
vm.swappiness = 0
net.ipv4.neigh.default.gc_stale_time = 120
net.ipv4.conf.all.rp_filter = 0
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.default.arp_announce = 2
net.ipv4.conf.lo.arp_announce = 2
net.ipv4.conf.all.arp_announce = 2
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 1024
net.ipv4.tcp_synack_retries = 2
error: "net.ipv6.conf.all.disable_ipv6" is an unknown key
error: "net.ipv6.conf.default.disable_ipv6" is an unknown key
error: "net.ipv6.conf.lo.disable_ipv6" is an unknown key
kernel.sysrq = 1
kernel.pid_max = 1000000
[root@smart0002 ~]#

CentOS大量cache内存如何处理?

【问题缘起】
  使用CentOS时发现,经常会出现top查看可用内存剩余很少的情况,然后free一看就是下面这种情况(大部分剩余内存都在cached里面),这种情况怎么处理呢?

1
2
3
4
5
6
[root@smart0003 local]# free -m
total used free shared buffers cached
Mem: 8001 5510 2491 0 91 2125
-/+ buffers/cache: 3293 4708
Swap: 0 0 0
[root@smart0003 local]#

【解决方法】
  实际上因为LINUX的内核机制导致出现这种缓存现状,而这些cache起来的内存是可以增加文件的读写速度的,一般情况下不需要特意去释放已经使用的cache。
  如果非要释放,也是可以通过几条命令实现的(注:释放前最好sync一下,防止丢数据);具体的操作命令如下:

1
2
3
4
5
6
7
8
9
10
11
# 释放网页缓存(To free pagecache); sync命令用于强制被改变的内容立刻写入磁盘,更新超块信息
sync
echo 1 > /proc/sys/vm/drop_caches

# 释放目录项和索引(To free dentries and inodes)
sync
echo 2 > /proc/sys/vm/drop_caches

# 释放网页缓存,目录项和索引(To free pagecache,dentries and inodes)
sync
echo 3 > /proc/sys/vm/drop_caches

MySQL锁表了或卡死了如何处理?

【问题缘起】
  曾几何时,大家想必都遇到过想在数据库中改一条测试数据却迟迟无法提交的问题吧?又或者是突然发现数据库卡到你怀疑人生,这个时候要怎么办呢?

【解决方法】
  首先我们一般需要查看一下当前的process,也就是下面的列表;通过Command和Info基本可以判断是什么操作,有没有锁表或者大量占用CPU(曾经我们测试库就因为数据团队大量同步数据入库导致数据库服务器直接宕机的情况);到这一步基本能找到出问题的连接和操作了,接下来暴力一点的方式就是直接kill了,如果不想采用这么暴力的方式,则可以从源头上看到底是哪个地方触发了这个操作(当然即使kill解决了当前问题,事后也需要分析以避免问题再次出现);以下操作仅供参考。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
[root@smart0002 ~]# mysql -u root -p
Enter password:
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 4693
Server version: 5.7.24-log MySQL Community Server (GPL)

Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show full processlist;
+------+------+---------------------+-----------+---------+------+----------+-----------------------+
| Id | User | Host | db | Command | Time | State | Info |
+------+------+---------------------+-----------+---------+------+----------+-----------------------+
| 4102 | root | 218.2.198.246:60014 | linc-test | Sleep | 3009 | | NULL |
| 4188 | root | 120.27.231.47:40642 | linc-test | Sleep | 1 | | NULL |
......
| 4688 | root | 218.2.198.246:54642 | linc-test | Sleep | 404 | | NULL |
| 4689 | root | 218.2.198.246:54667 | linc-test | Sleep | 400 | | NULL |
| 4691 | root | 218.2.198.246:54487 | linc-test | Sleep | 349 | | NULL |
| 4692 | root | 218.2.198.246:55163 | linc-test | Sleep | 50 | | NULL |
| 4693 | root | localhost | NULL | Query | 0 | starting | show full processlist |
+------+------+---------------------+-----------+---------+------+----------+-----------------------+
47 rows in set (0.00 sec)

mysql> kill 4692;
Query OK, 0 rows affected (0.01 sec)

mysql>

------2019 Lin.C ------