简介

linux最大打开文件句柄数,即打开文件数最大限制,就是规定的单个进程能够打开的最大文件句柄数量(Socket连接也算在里面,默认大小1024)

为了防止失控的进程破坏系统的性能,UnixLinux 跟踪进程使用的大部分资源,允许用户和系统管理员使用对进程的资源限制,
设置的限制有两种:硬限制软限制:

  • hard:硬限制是可以在任何时候任何进程中设置 但硬限制只能由超级用户修改。
  • soft:软限制是内核实际执行的限制,任何进程都可以将软限制设置为任意小于等于对进程限制的硬限制的值。

(noproc)最大线程数和(nofile)文件数。

1
2
3
4
5
6
# nr_open是单个进程可分配的最大文件数
# 一般默认为:1024*1024=1048576
cat /proc/sys/fs/nr_open

# file-max是内核可分配的最大文件数
cat /proc/sys/fs/file-max

在Linux下有时会遇到 Socket/File : Can't open so many files 的问题。其实Linux是有文件句柄限制的,而且Linux默认一般都是1024(阿里云主机默认是65535)。在生产环境中很容易到达这个值,因此这里就会成为系统的瓶颈。

Linux资源的限制

登陆时限制

Linux对用户使用资源的限制通过 PAM 对登陆用户进行身份验证并设置相应的限制。

具体顺序如下。从用户登陆开始,操作系统会依次执行如下三部

    1. /etc/pam.d/login
    1. /etc/pam.d/system-auth
    1. /lib64/security/pam_limits.so

1,/etc/pam.d/login 中调用system-auth

1
cat /etc/pam.d/login

微信截图_20201224172412.png

2,在/etc/pam.d/system-auth 调用 pam_limits.so

1
/etc/pam.d/system-auth

微信截图_20201224172513.png

3,通过grep查看 /lib64/security/pam_limits.so 可以看到 limits.conf和limits.d/*.conf

1
grep -a "/etc/security/limits." /lib64/security/pam_limits.so

微信截图_20201224172633.png

Centos7系统修改

在Centos7系统中,使用 Systemd 替代了之前的 SysV。/etc/security/limits.conf 文件的配置作用域缩小了。/etc/security/limits.conf 的配置,只适用于通过PAM认证登录用户的资源限制,它对 systemdservice 的资源限制不生效。因此登录用户的限制,通过 /etc/security/limits.conf/etc/security/limits.d 下的文件设置即可。

对于 systemd service 的资源设置,则需修改全局配置,全局配置文件放在 /etc/systemd/system.conf/etc/systemd/user.confsystem.conf 是系统实例使用的,user.conf 是用户实例使用的。

1
2
3
4
# vim /etc/systemd/system.conf
[Manager]
DefaultLimitNOFILE=1048576
DefaultLimitNPROC=1048576

reboot 重启后生效。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@host-192-175-32-22 bin]# cat /proc/2789/limits
Limit Soft Limit Hard Limit Units
Max cpu time unlimited unlimited seconds
Max file size unlimited unlimited bytes
Max data size unlimited unlimited bytes
Max stack size 8388608 unlimited bytes
Max core file size 0 unlimited bytes
Max resident set unlimited unlimited bytes
Max processes 1048576 1048576 processes
Max open files 1048576 1048576 files
Max locked memory 65536 65536 bytes
Max address space unlimited unlimited bytes
Max file locks unlimited unlimited locks
Max pending signals 127951 127951 signals
Max msgqueue size 819200 819200 bytes
Max nice priority 0 0
Max realtime priority 0 0
Max realtime timeout unlimited unlimited us
[root@host-192-175-32-22 bin]# ulimit -n
1048576

Red Hat系统修改

查看 /etc/sysctl.conf/etc/sysctl.d/*.conf 的设置,修改 sysctl.conf,修改后须执行 sysctl -p 使修改生效。

1
fs.file-max=6523120

查看 /etc/security/limits.conf 以及 /etc/security/limits.d/*.conf 。操作系统默认先加载 limits.conf 后加载 limits.d/*.conf,所以相同配置后面会覆盖前面,如:/etc/security/limits.d/90-nproc.conf

1
2
*          -       nofile    1048576
* - nproc 1048576

免密登陆

用户不会进行登陆验证过程,所以不会加载 limits.conf 文件,建议通过 /etc/profile 添加 ulimit -n 1048576 命令设置,重新登陆或者执行 source /etc/profile 命令,然后启动服务程序;

查看用户级的最大限制

ulimit -a 或者 ulimit -n

ulimit -n,默认是1024,向阿里云华为云这种云主机一般是 65535。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@host-192-125-30-59 ~]# ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 256967
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 256967
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
[root@host-192-125-30-59 ~]# ulimit -n
1024

open files (-n)1024 是linux操作系统对一个进程打开的文件句柄数量的限制(也包含打开的套接字数量)

选项 [options] 含义 例子
-H 设置硬资源限制,一旦设置不能增加。 ulimit – Hs 64;限制硬资源,线程栈大小为 64K。
-S 设置软资源限制,设置后可以增加,但是不能超过硬资源设置。 ulimit – Sn 32;限制软资源,32 个文件描述符。
-a 显示当前所有的 limit 信息。 ulimit – a;显示当前所有的 limit 信息。
-c 最大的 core 文件的大小, 以 blocks 为单位。 ulimit – c unlimited; 对生成的 core 文件的大小不进行限制。
-d 进程最大的数据段的大小,以 Kbytes 为单位。 ulimit -d unlimited;对进程的数据段大小不进行限制。
-f 进程可以创建文件的最大值,以 blocks 为单位。 ulimit – f 2048;限制进程可以创建的最大文件大小为 2048 blocks。
-l 最大可加锁内存大小,以 Kbytes 为单位。 ulimit – l 32;限制最大可加锁内存大小为 32 Kbytes。
-m 最大内存大小,以 Kbytes 为单位。 ulimit – m unlimited;对最大内存不进行限制。
-n 可以打开最大文件描述符的数量。 ulimit – n 128;限制最大可以使用 128 个文件描述符。
-p 管道缓冲区的大小,以 Kbytes 为单位。 ulimit – p 512;限制管道缓冲区的大小为 512 Kbytes。
-s 线程栈大小,以 Kbytes 为单位。 ulimit – s 512;限制线程栈的大小为 512 Kbytes。
-t 最大的 CPU 占用时间,以秒为单位。 ulimit – t unlimited;对最大的 CPU 占用时间不进行限制。
-u 用户最大可用的进程数。 ulimit – u 64;限制用户最多可以使用 64 个进程。
-v 进程最大可用的虚拟内存,以 Kbytes 为单位。 ulimit – v 200000;限制最大可用的虚拟内存为 200000 Kbytes。

查看某个进程的最大打开文件数和当前打开文件数

先找到该进程的进程号,然后查看

1
2
3
4
5
6
7
8
# 找到pid
ps -aux

# /proc/[pid]/limits和fd

cat /proc/[pid]/limits 显示当前进程的资源限制

ls /proc/[pid]/fd 是一个目录,包含进程打开文件的情况

实例:

1
2
3
4
[root@host-192-125-30-59 ~]# cat /proc/3289/limits| grep files
Max open files 1024 4096 files
[root@host-192-125-30-59 ~]# ll /proc/3289/fd | wc -l
7

ps:如果要查看某个进程的线程的详细信息,/proc/[pid]/task

修改用户级最大限制

临时生效方法:(重启后失效)

这个设置是暂时的保留。当退出Shell会话后,该值恢复原值。

1
ulimit -SHn 1048576

ulimit 命令分软限制和硬限制,加 -H 就是硬限制,加 -S 就是软限制。默认显示的是软限制,如果运行 ulimit 命令修改时没有加上 -H-S ,就是两个参数一起改变。

硬限制就是实际的限制,而软限制是警告限制,它只会给出警告。

用户级修改永久有效方式

修改配置文件 vim /etc/security/limits.conf,加入:

1
2
3
4
5
6
7
8
* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535

# 可以使用下面一行来替代上面
* - nofile 65535
* - nproc 65535

或者使用命令:

1
2
echo "* soft nofile 65535" >> /etc/security/limits.conf
echo "* hard nofile 65535" >> /etc/security/limits.conf

* 表示所用的用户,但有的系统不认, 需要具体的用户名, 比如:

1
2
root soft nofile 65535
root hard nofile 65535

有些环境修改后,root用户需要重启机器才生效,而普通用户重新登录后即生效。

需要小心注意的是,有些环境上面这样做,可能导致无法ssh登录,所以在修改时最好打开两个窗口,万一登录不了还可自救。

修改系统级最大限制

其实上面的修改都是对一个进程打开的文件句柄数量的限制,我们还需要设置系统的总限制才可以。

假如,我们设置进程打开的文件句柄数是 1024 ,但是系统总限制才500,所以所有进程最多能打开文件句柄数量500。从这里我们可以看出只设置进程的打开文件句柄的数量是不行的。所以需要修改系统的总限制才可以。

1
2
3
4
5
6
7
# 系统级修改临时生效方式:
echo 6523120 > /proc/sys/fs/file-max

# 系统级修改永久生效方式:
vim /etc/sysctl.conf
# 加入
fs.file-max=6523120

查看系统级文件句柄修改,是否生效

1
sysctl -p

参考:

Linux最大文件打开数

linux最大打开文件句柄数

修改RedHat 7.2 进程最大句柄数限制

Shell 的 echo 指令与 PHP 的 echo 指令类似,都是用于字符串的输出。命令格式:

1
echo string

Shell符号注解

1
2
3
4
5
6
> 重定向输出到某个位置,替换原有文件的所有内容。
>> 重定向追加到某个位置,在原有文件的末尾添加内容。
< 重定向输入某个位置文件。
2> 重定向错误输出。
2>> 重定向错误追加输出到文件末尾。
&> 混合输出错误的和正确的都输出。

echo输出的字符串总结:

===================================================================

符号 能否引用变量 能否引用转移符 能否引用文本格式符(如:换行符、制表符)
单引号
双引号
无引号

===================================================================

1.显示普通字符串

1
echo "It is a test"

这里的双引号完全可以省略,以下命令与上面实例效果一致:

1
echo It is a test

2.显示转义字符

1
echo "\"It is a test\""

结果将是:

1
"It is a test"

同样,双引号也可以省略

3.显示变量

read 命令从标准输入中读取一行,并把输入行的每个字段的值指定给 shell 变量

read 命令一个一个词组地接收输入的参数,每个词组需要使用空格进行分隔;如果输入的词组个数大于需要的参数个数,则多出的词组将被作为整体为最后一个参数接收。

read 参数说明:

1
2
3
4
-p 输入提示文字
-n 输入字符长度限制(达到6位,自动结束)
-t 输入限时
-s 隐藏输入内容

示例:

1
2
3
#!/bin/sh
read name
echo "$name It is a test"

以上代码保存为 test.sh,name 接收标准输入的变量,结果将是:

1
2
3
[root@www ~]# sh test.sh
OK #标准输入
OK It is a test #输出

4.显示换行

1
2
echo -e "OK! \n" # -e 开启转义
echo "It is a test"

输出结果:

1
2
3
OK!

It is a test

5.显示不换行

1
2
3
#!/bin/sh
echo -e "OK! \c" # -e 开启转义 \c 不换行
echo "It is a test"

输出结果:

1
OK! It is a test

6.显示结果定向至文件

1
echo "It is a test" > myfile

7.原样输出字符串,不进行转义或取变量(用单引号)

1
echo '$name\"'

输出结果:

1
$name\"

8.显示命令执行结果

1
echo `date`

注意: 这里使用的是反引号 `, 而不是单引号 ‘。

结果将显示当前日期

1
Thu Jul 24 10:08:46 CST 2014

参考:

Shell echo命令

修改系统参数

修改最大可打开文件数

参考:Linux最大文件打开数

TCP监听队列大小

参考:Linux设置TCP监听队列

在 /etc/sysctl.conf 添加:

net.core.somaxconn=65000

执行命令 sysctl -p 以生效

OOM相关:vm.overcommit_memory

参考:Linux OOM机制简介

在 /etc/sysctl.conf 添加:

vm.overcommit_memory=1

执行命令 sysctl -p 以生效

Linux Transparent HugePages(透明大页)

参考:Linux Transparent HugePages(透明大页)

将 echo never > /sys/kernel/mm/transparent_hugepage/enabled 加入到文件 /etc/rc.local 中

目录结构

完成公共的 redis.conf 和一个端口号的,如 redis-6379.conf,其它端口号的配置文件基于一个修改后的端口号配置文件即可。

1
2
[root@host-192-125-30-59 redis-cluster]# ls
data log redis-6379.conf redis-6380.conf redis-6381.conf redis.conf
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
# 创建目录
mkdir /usr/local/redis-cluster
cd /usr/local/redis-cluster
mkdir -p data log

cd /usr/local/redis-cluster/data
mkdir -p 6379 6380 6381

cd /usr/local/redis-cluster

# 生成共有配置文件
touch redis.conf

# 生成端口文件
touch redis-6379.conf

# 生成不同端口的配置文件
sed 's/6379/6380/g' redis-6379.conf > /usr/local/redis-cluster/redis-6380.conf
sed 's/6379/6381/g' redis-6379.conf > /usr/local/redis-cluster/redis-6381.conf

# 启动
/usr/local/bin/redis-server /usr/local/redis-cluster/redis-6379.conf
/usr/local/bin/redis-server /usr/local/redis-cluster/redis-6380.conf
/usr/local/bin/redis-server /usr/local/redis-cluster/redis-6381.conf

# 连接单个节点
/usr/local/bin/redis-cli -h 127.0.0.1 -p 6379 -a test

# 停止
/usr/local/bin/redis-cli -h 127.0.0.1 -p 6379 -a test shutdown

查看redis运行情况:

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
netstat -tunpl | grep 6379
netstat -tunpl | grep 6380
netstat -tunpl | grep 6381
ps aux | grep redis

[root@host-192-125-30-111 redis-cluster]# netstat -tunpl | grep 6379
tcp 0 0 0.0.0.0:16379 0.0.0.0:* LISTEN 6184/redis-server *
tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN 6184/redis-server *
tcp6 0 0 :::16379 :::* LISTEN 6184/redis-server *
tcp6 0 0 :::6379 :::* LISTEN 6184/redis-server *
[root@host-192-125-30-111 redis-cluster]# netstat -tunpl | grep 6380
tcp 0 0 0.0.0.0:16380 0.0.0.0:* LISTEN 6189/redis-server *
tcp 0 0 0.0.0.0:6380 0.0.0.0:* LISTEN 6189/redis-server *
tcp6 0 0 :::16380 :::* LISTEN 6189/redis-server *
tcp6 0 0 :::6380 :::* LISTEN 6189/redis-server *
[root@host-192-125-30-111 redis-cluster]# netstat -tunpl | grep 6381
tcp 0 0 0.0.0.0:16381 0.0.0.0:* LISTEN 6194/redis-server *
tcp 0 0 0.0.0.0:6381 0.0.0.0:* LISTEN 6194/redis-server *
tcp6 0 0 :::16381 :::* LISTEN 6194/redis-server *
tcp6 0 0 :::6381 :::* LISTEN 6194/redis-server *
[root@host-192-125-30-111 redis-cluster]# ps aux|grep redis
root 6184 0.0 0.0 156964 7724 ? Ssl 10:38 0:00 /usr/local/bin/redis-server *:6379 [cluster]
root 6189 0.0 0.0 153892 7692 ? Ssl 10:39 0:00 /usr/local/bin/redis-server *:6380 [cluster]
root 6194 0.0 0.0 153892 7692 ? Ssl 10:39 0:00 /usr/local/bin/redis-server *:6381 [cluster]
root 6339 0.0 0.0 112724 992 pts/1 S+ 10:42 0:00 grep --color=auto redis

配置redis

指定端口的配置文件 redis-PORT.conf
该文件定义所有与端口相关的配置项,PORT需要替换为具体的端口,如6379

公共配置 :redis.conf

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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# Redis configuration file example.
#
# Note that in order to read the configuration file, Redis must be
# started with the file path as first argument:
#
# ./redis-server /path/to/redis.conf

# Note on units: when memory size is needed, it is possible to specify
# it in the usual form of 1k 5GB 4M and so forth:
#
# 1k => 1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb => 1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024 bytes
#
# units are case insensitive so 1GB 1Gb 1gB are all the same.

# 建议
# 1,引用公共的配置文件,建议为全路径值
# include redis.conf

# yes表示以集群方式运行,为no表示以非集群方式运行
cluster-enabled yes

# 日志级别,建议为notice,
# 另外注意redis是不会滚动日志文件的,每次写日志都是先打开日志文件再写日志再关闭方式
# debug
# verbose
# notice
# warning
loglevel notice

# 密码
requirepass password

# 主库master要求密码验证,从库配置文件中 master 密码配置
masterauth password

# 可选
# 最大连接数
maxclients 1000000

# 可选
# 客户端多长(秒)时间没发包过来关闭它,0表示永不关闭
timeout 0

# 集群中的节点最大不可用时长,在这个时长内,不会被判定为fail。
# 对于master节点,当不可用时长超过此值时,slave在延迟至少0.5秒后会发起选举
# 进行failover成为master。Redis集群的很多其它值与cluster-node-timeout有关。
cluster-node-timeout 15000

# 5.0 以下使用cluster-slave-validity-factor
# 如果设置为0,则slave总是尝试成为master,无论slave和master间的链接断开时间的长短。
# 如果是一个大于0的值,则最大可断开时长为:(cluster-slave-validity-factor * cluster-node-timeout)。
# 例如:当cluster-node-timeout值为5,cluster-slave-validity-factor值为10时,
# slave和master间的连接断开50秒内,slave不会尝试成为master。
cluster-replica-validity-factor 0

# 这个参数一定不能小于repl-ping-replica-period,
# 可以考虑为repl-ping-replica-period的3倍或更大。定义多长时间内均PING不通时,
# 判定心跳超时。对于redis集群,达到这个值并不会发生主从切换,主从何时切换由
# 参数cluster-node-timeout控制,只有master状态为fail后,它的slaves才能发起选举。
repl-timeout 10

# 5.0 以下使用 repl-ping-slave-period
# 定义slave多久(秒)ping一次master,如果超过repl-timeout指定的时长都没有收到响应,
# 则认为master挂了
repl-ping-replica-period 10

# 5.0 以下使用 slave-read-only
# slave是否只读
replica-read-only yes

# 5.0 以下使用 slave-serve-stale-data
# 当slave与master断开连接,slave是否继续提供服务
replica-serve-stale-data yes

# 5.0 以下使用 slave-priority
# slave权重值,当master挂掉,只有权重最大的slave接替master
replica-priority 100

# 4.0新增配置项,用于控制是否启用RDB-AOF混用,值为no表示关闭
aof-use-rdb-preamble yes

# 当同时写AOF或RDB,则redis启动时只会加载AOF,AOF包含了全量数据。
# 如果当队列使用,入队压力又很大,建议设置为no
appendonly yes

# 可取值everysec,其中no表示由系统自动,
# 当写压力很大时,建议设置为no,否则容易造成整个集群不可用
# appendfsync always
# appendfsync everysec
# appendfsync no
appendfsync everysec

# 以守护进程运行 Redis 实例
# 相关配置项pidfile
daemonize yes

# 3.2.0新增的配置项,默认值为yes,限制从其它机器登录Redis server,而只能从127.0.0.1登录。
protected-mode no

# 取值不能超过系统的/proc/sys/net/core/somaxconn
# 此参数是指:已完成三次握手的TCP连接队列,默认值511,
# 但是Linux系统内核参数socket最大连接的值默认是128,对应文件/proc/sys/net/core/somaxconn,
# 当系统并发量大且客户端连接缓慢时,应该将两个值进行参考设置。
tcp-backlog 511

# 设置自动rewite AOF文件(手工rewrite只需要调用命令BGREWRITEAOF)
auto-aof-rewrite-percentage 100

# 触发rewrite的AOF文件大小,只有大于此大小时才会触发rewrite
auto-aof-rewrite-min-size 64mb

# 子进程在做rewrite时,主进程不调用fsync(由内核默认调度)
no-appendfsync-on-rewrite no

# 如果因为磁盘故障等导致保存rdb失败,停止写操作,可设置为NO。
stop-writes-on-bgsave-error yes

# 为no表示有slots不可服务时其它slots仍然继续服务,建议值为no,以提供最高的可用性
cluster-require-full-coverage no

# 设置最大的内存,单位为字节
# 26843545600(25GB)
# 19327352832(18GB)
# 注意,在 64bit 系统下,maxmemory 设置为 0 表示不限制 Redis 内存使用,
# 在 32bit 系统下,maxmemory 隐式不能超过 3GB。
maxmemory 19327352832

# 设置达到最大内存时的淘汰策略
maxmemory-policy volatile-lru

# 设置master端的客户端缓存,三种:normal、replica和pubsub
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit replica 256mb 64mb 60
client-output-buffer-limit pubsub 32mb 8mb 60

# 最少slave(replica)数,用来保证集群中不会有裸奔的master。当某个master节点的slave(replica)节点挂掉裸奔后,
# 会从其他富余的master节点分配一个slave(replica)节点过来,确保每个master节点都有至少一个slave(replica)节点,
# 不至于因为master节点挂掉而没有相应slave(replica)节点替换为master节点导致集群崩溃不可用。
cluster-migration-barrier 1

# 当slave(replica)失联时的,环形复制缓区大小,值越大可容忍更长的slave(replica)失联时长
repl-backlog-size 1mb

# slave失联的时长达到该值时,释放backlog缓冲区
# repl-backlog-ttl 3600

# 刷新快照(RDB)到磁盘的策略,根据实际调整值,
# “save 900 1”表示900秒后至少有1个key被修改才触发save操作,其它类推。
# 注意执行flushall命令也会产生RDB文件,不过是空文件。
# 如果不想生成RDB文件,可以将save全注释掉。
save 900 1
save 300 10
save 60 10000

禁止指定命令

KEYS命令很耗时,FLUSHDB和FLUSHALL命令可能导致误删除数据,所以线上环境最好禁止使用,可以在Redis配置文件增加如下配置:

1
2
3
rename-command KEYS ""
rename-command FLUSHDB ""
rename-command FLUSHALL ""

端口配置:redis-PORT.conf

注:PORT 需要改成具体端口;

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
# 1,引用公共的配置文件,建议为全路径值
include /usr/local/redis-cluster/redis.conf

# 必须
# 端口号
port PORT

# 必须
# 默认放在dir指定的目录,注意不能包含目录,纯文件名,为redis-server进程自动维护,不能手工修改
cluster-config-file nodes-PORT.conf

# 可选
# 只有当daemonize值为yes时,才有意义;并且这个要求对目录/var/run有写权限,否则可以考虑设置为/# tmp/redis-PORT.pid,或者放在bin或log目录下,如:/data/redis/log/redis-PORT.pid。只有当配# 置项daemonize的值为yes时,才会产生这个文件。
pidfile /var/run/redis-PORT.pid

# 工作目录。
#
# DB 将写入此目录,并指定文件名
# 以上使用"dbfilename"配置指令。
#
# 仅追加文件也将在此目录中创建。
#
# 请注意,您必须在此处指定目录,而不是文件名。
dir /usr/local/redis-cluster/data/PORT

# 纯文件名,位于dir指定的目录下,不能包含目录,
# 否则报错“appendfilename can't be a path, just # a filename”。
# 如果开启了AOF,REdis进程启动时并不会读取RDB文件,
# 所以配置上可以考虑关闭RDB,这样可以提升REdis稳定性。
dbfilename dump-PORT.rdb

# 纯文件名,位于dir指定的目录下,不能包含目录,
# 否则报错“appendfilename can't be a path, just a filename”
appendfilename "appendonly-PORT.aof"

# 日志文件,包含目录和文件名,注意redis不会自动滚动日志文件
logfile /usr/local/redis-cluster/log/redis-PORT.log

创建和启动redis集群

加上进程监控

使用 https://github.com/eyjian/libmooon/blob/master/shell/process_monitor.sh

监控示例:

1
2
3
4
REDIS_HOME=/usr/local
* * * * * /usr/local/bin/process_monitor.sh "$REDIS_HOME/bin/redis-server 6379" "$REDIS_HOME/bin/redis-server $REDIS_HOME/redis-cluster/redis-6379.conf"
* * * * * /usr/local/bin/process_monitor.sh "$REDIS_HOME/bin/redis-server 6380" "$REDIS_HOME/bin/redis-server $REDIS_HOME/redis-cluster/redis-6380.conf"
* * * * * /usr/local/bin/process_monitor.sh "$REDIS_HOME/bin/redis-server 6381" "$REDIS_HOME/bin/redis-server $REDIS_HOME/redis-cluster/redis-6381.conf"

注意:redis的日志文件不会自动滚动,redis-server 每次在写日志时,均会以追加方式调用fopen写日志,而不处理滚动。
也可借助linux自带的 logrotate 来滚动redis日志,命令 logrotate 一般位于目录 /usr/sbin 下。

滚动日志(可选):

1
2
3
* * * * * log=$REDIS_HOME/redis-cluster/log/redis-6379.log;if test `ls -l $log|cut -d' ' -f5` -gt 104857600; then mv $log $log.old; fi
* * * * * log=$REDIS_HOME/redis-cluster/log/redis-6380.log;if test `ls -l $log|cut -d' ' -f5` -gt 104857600; then mv $log $log.old; fi
* * * * * log=$REDIS_HOME/redis-cluster/log/redis-6381.log;if test `ls -l $log|cut -d' ' -f5` -gt 104857600; then mv $log $log.old; fi

Redis集群TCP端口(Redis Cluster TCP ports)

每个Redis集群中的节点都需要打开两个TCP连接。一个连接用于正常的给Client提供服务,比如6379,还有一个额外的端口(通过在这个端口号上加10000)作为数据端口,比如16379。第二个端口(本例中就是16379)用于集群总线,这是一个用二进制协议的点对点通信信道。这个集群总线(Cluster bus)用于节点的失败侦测、配置更新、故障转移授权,等等。客户端从来都不应该尝试和这些集群总线端口通信,它们只应该和正常的Redis命令端口进行通信。注意,确保在你的防火墙中开放着两个端口,否则,Redis集群节点之间将无法通信。

命令端口和集群总线端口的偏移量总是10000。

注意,如果想要集群按照你想的那样工作,那么集群中的每个节点应该:

正常的客户端通信端口(通常是6379)用于和所有可到达集群的所有客户端通信
集群总线端口(the client port + 10000)必须对所有的其它节点是可到达的
也就是,要想集群正常工作,集群中的每个节点需要做到以下两点:

正常的客户端通信端口(通常是6379)必须对所有的客户端都开放,换言之,所有的客户端都可以访问
集群总线端口(客户端通信端口 + 10000)必须对集群中的其它节点开放,换言之,其它任意节点都可以访问
如果你没有开放TCP端口,你的集群可能不会像你期望的那样工作。集群总线用一个不同的二进制协议通信,用于节点之间的数据交换。

快速创建,启动redis集群

如果只是想快速创建和启动redis集群,而不关心过程,可使用redis官方提供的脚本 create-cluster,两步完成:

1
2
create-cluster start
create-cluster create

第二步 create-cluster create 是一个交互式过程,当提示时,请输入 yes 再回车继续,第一个节点的端口号为 30001,一共会启动六个redis节点。

create-cluster位于redis源代码的 utils/create-cluster 目录下,是一个bash脚本文件。

停止集群:create-cluster stop

创建redis cluster

1
2
# 注:由于只有两台服务器,故在服务器1上部署两个主节点,一个从节点,服务器2上部署两个从节点,一个主节点。
/usr/local/bin/redis-cli --cluster create 192.125.30.111:6379 192.125.30.111:6380 192.125.30.59:6381 192.125.30.59:6379 192.125.30.59:6380 192.125.30.111:6381 --cluster-replicas 1

如果群集设置着密码,需要使用 -a 密码,否则会报错:(error)NOAUTH Authentication required:

1
/usr/local/bin/redis-cli -a test --cluster create 192.125.30.111:6379 192.125.30.111:6380 192.125.30.59:6381 192.125.30.59:6379 192.125.30.59:6380 192.125.30.111:6381 --cluster-replicas 1

注意:如果报以下错误,需要停止单个redis节点,并把对应的数据目录删除重建。

1
2
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
[ERR] Node 192.125.30.59:6381 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.
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@host-192-125-30-111 ~]# ps aux | grep redis
root 10547 0.0 0.0 112724 988 pts/0 R+ 11:03 0:00 grep --color=auto redis
root 17367 0.1 0.0 156452 7920 ? Ssl 8月15 3:56 /usr/local/bin/redis-server *:6379 [cluster]
root 17372 0.1 0.0 153892 7844 ? Ssl 8月15 3:21 /usr/local/bin/redis-server *:6380 [cluster]
root 17377 0.1 0.0 153892 7848 ? Ssl 8月15 3:20 /usr/local/bin/redis-server *:6381 [cluster]
[root@host-192-125-30-111 ~]# kill -9 17367
[root@host-192-125-30-111 ~]# kill -9 17372
[root@host-192-125-30-111 ~]# kill -9 17377

# 删除数据目录
[root@host-192-125-30-111 ~]# cd /usr/local/
[root@host-192-125-30-111 local]# ls
bin etc games include lib lib64 libexec redis-cluster sbin share src
[root@host-192-125-30-111 local]# cd redis-cluster
[root@host-192-125-30-111 redis-cluster]# ls
data log redis-6379.conf redis-6380.conf redis-6381.conf redis.conf
[root@host-192-125-30-111 redis-cluster]# cd data
[root@host-192-125-30-111 data]# ls
6379 6380 6381
[root@host-192-125-30-111 data]# rm -rf 63*
[root@host-192-125-30-111 data]# ls
[root@host-192-125-30-111 data]# mkdir -p 6379 6380 6381
[root@host-192-125-30-111 data]# cd ..
[root@host-192-125-30-111 redis-cluster]# ls
data log redis-6379.conf redis-6380.conf redis-6381.conf redis.conf
[root@host-192-125-30-111 redis-cluster]# cd log
[root@host-192-125-30-111 log]# ls
redis-6379.log redis-6380.log redis-6381.log
[root@host-192-125-30-111 log]# rm -rf redis-*.log
[root@host-192-125-30-111 log]# ls
[root@host-192-125-30-111 log]#

redis-cli 的参数说明:

1
2
3
4
5
# 表示创建一个redis集群。
create

# 表示为集群中的每一个主节点指定一个从节点,即一比一的复制。
--cluster-replicas 1

注意:如果配置项 cluster-enabled 的值不为yes,则执行时会报错 [ERR] Node 192.168.0.251:6381 is not configured as a cluster node.

输出:

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
[root@host-192-125-30-111 redis-cluster]# /usr/local/bin/redis-cli -a Perfect1 --cluster create 192.125.30.111:6379 192.125.30.111:6380 192.125.30.59:6381 192.125.30.59:6379 192.125.30.59:6380 192.125.30.111:6381 --cluster-replicas 1
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 192.125.30.59:6380 to 192.125.30.111:6379
Adding replica 192.125.30.111:6381 to 192.125.30.59:6381
Adding replica 192.125.30.59:6379 to 192.125.30.111:6380
M: 9df266851fa7d8d9363d584a5bc644f36ea1d052 192.125.30.111:6379
slots:[0-5460] (5461 slots) master
M: 932a6ab157056e2d36e3915780b5d77138bbabdb 192.125.30.111:6380
slots:[10923-16383] (5461 slots) master
M: fb9923083a70ca2131b3fb6c7633bc7275dfe33c 192.125.30.59:6381
slots:[5461-10922] (5462 slots) master
S: 53ab782834f304013ac055a35e5275e5004b30c7 192.125.30.59:6379
replicates 932a6ab157056e2d36e3915780b5d77138bbabdb
S: 7854f8ed0234945e89af5079331ce7779449d632 192.125.30.59:6380
replicates 9df266851fa7d8d9363d584a5bc644f36ea1d052
S: 1141e28e7b135db55cdb1c87c143ee0c0502d26d 192.125.30.111:6381
replicates fb9923083a70ca2131b3fb6c7633bc7275dfe33c
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
..
>>> Performing Cluster Check (using node 192.125.30.111:6379)
M: 9df266851fa7d8d9363d584a5bc644f36ea1d052 192.125.30.111:6379
slots:[0-5460] (5461 slots) master
1 additional replica(s)
S: 1141e28e7b135db55cdb1c87c143ee0c0502d26d 192.125.30.111:6381
slots: (0 slots) slave
replicates fb9923083a70ca2131b3fb6c7633bc7275dfe33c
M: 932a6ab157056e2d36e3915780b5d77138bbabdb 192.125.30.111:6380
slots:[10923-16383] (5461 slots) master
1 additional replica(s)
S: 7854f8ed0234945e89af5079331ce7779449d632 192.125.30.59:6380
slots: (0 slots) slave
replicates 9df266851fa7d8d9363d584a5bc644f36ea1d052
S: 53ab782834f304013ac055a35e5275e5004b30c7 192.125.30.59:6379
slots: (0 slots) slave
replicates 932a6ab157056e2d36e3915780b5d77138bbabdb
M: fb9923083a70ca2131b3fb6c7633bc7275dfe33c 192.125.30.59:6381
slots:[5461-10922] (5462 slots) master
1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

集群相关信息查看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 集群状态
/usr/local/bin/redis-cli -h 127.0.0.1 -p 6379 -a password cluster info

# 集群节点信息
/usr/local/bin/redis-cli -h 127.0.0.1 -p 6379 -a password cluster nodes

# 节点内存、cpu、key数量等信息(每个节点都需查看)
/usr/local/bin/redis-cli -h 127.0.0.1 -p 6379 -a password info

# 连接单个节点
/usr/local/bin/redis-cli -h 127.0.0.1 -p 6379 -a test

# 连接群集
/usr/local/bin/redis-cli -c -h 127.0.0.1 -p 6379 -a test

ps aux|grep redis-server

查看redis进程是否已切换为集群状态(cluster)

停止redis实例,直接使用kill命令即可,如:kill 3825,重启和单机版相同。

从slaves读数据

默认不能从slaves读取数据,但建立连接后,执行一次命令 READONLY ,即可从slaves读取数据。如果想再次恢复不能从slaves读取数据,可以执行下命令 READWRITE

群集操作

新增主(master)节点

注意一定要保证新节点里面没有添加过任何数据

以添加 192.168.0.251:6390 为例:

1
2
3
4
5
# 192.168.0.251:6381 为集群中任一可用的节点
redis-cli --cluster add-node 192.168.0.251:6390 192.168.0.251:6381

# 查看
redis-cli -c -p 6381 cluster nodes|grep master

新加入的master节点上没有任何数据(slots,运行redis命令cluster nodes可以看到这个情况)。当一个slave想成为master时,由于这个新的master节点不管理任何slots,它不参与选举。可以使用redis-cli的reshard为这个新master节点分配slots,如:

1
redis-cli --cluster reshard 192.168.0.251:6390

新增从(slave)节点

以添加 192.168.0.251:6390 为例:

1
redis-cli --cluster add-node 192.168.0.251:6390 192.168.0.251:6381 --cluster-slave

192.168.0.251:6390 为新添加的从节点,192.168.0.251:6381 可为集群中已有的任意节点,这种方法随机为6390指定一个master,如果想明确指定master,假设目标master的ID为3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e,则:

1
redis-cli --cluster add-node 192.168.0.251:6390 192.168.0.251:6381 --cluster-slave --cluster-master-id 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e

删除节点

从集群中删除一个节点命令格式:

1
2
# 127.0.0.1:7000 为集群中任意一个非待删除节点,node-id 为待删除节点的ID。
redis-cli --cluster del-node 127.0.0.1:7000 `<node-id>`

如果待删除的是master节点,则在删除之前需要将该master负责的slots先全部迁到其它master。

1
2
3
4
5
6
7
$ ./redis-cli --cluster del-node 192.168.0.251:6381 082c079149a9915612d21cca8e08c831a4edeade

>>> Removing node 082c079149a9915612d21cca8e08c831a4edeade from cluster 192.168.0.251:6381

>>> Sending CLUSTER FORGET messages to the cluster...

>>> SHUTDOWN the node.

如果删除后,其它节点还看得到这个被删除的节点,则可通过FORGET命令解决,需要在所有还看得到的其它节点上执行:

CLUSTER FORGET <node-id>

FORGET做两件事:

  1. 从节点表剔除节点;

  2. 在60秒的时间内,阻止相同ID的节点加进来。

slots相关命令

1
2
3
4
5
CLUSTER ADDSLOTS slot1 [slot2] ... [slotN]
CLUSTER DELSLOTS slot1 [slot2] ... [slotN]
CLUSTER SETSLOT slot NODE node
CLUSTER SETSLOT slot MIGRATING node
CLUSTER SETSLOT slot IMPORTING node

参考:

Redis-5.0.0集群配置

Redis集群

分布式缓存 Redis 集群搭建

redis集群配置文件

Redis详解(二)– redis的配置文件介绍

高可用Redis(十一):使用redis-trib.rb工具搭建集群

Redis cluster tutorial

Redis Cluster Specification

Alpha:是内部测试版,一般不向外部发布,会有很多Bug.一般只有测试人员使用。

Beta:也是测试版,这个阶段的版本会一直加入新的功能。在Alpha版之后推出。

RC:(Release Candidate) 顾名思义么 ! 用在软件上就是候选版本。系统平台上就是发行候选版本。RC版不会再加入新的功能了,主要着重于除错。

GA:General Availability,正式发布的版本,在国外都是用GA来说明release版本的。

RTM:(Release to Manufacture)是给工厂大量压片的版本,内容跟正式版是一样的,不过RTM版也有出限制、评估版的。但是和正式版本的主要程序代码都是一样的。

OEM:是给计算机厂商随着计算机贩卖的,也就是随机版。只能随机器出货,不能零售。只能全新安装,不能从旧有操作系统升级。包装不像零售版精美,通常只有一面CD和说明书(授权书)。

RVL:号称是正式版,其实RVL根本不是版本的名称。它是中文版/英文版文档破解出来的。

EVAL:而流通在网络上的EVAL版,与“评估版”类似,功能上和零售版没有区别。

RTL:Retail(零售版)是真正的正式版,正式上架零售版。在安装盘的i386文件夹里有一个eula.txt,最后有一行EULAID,就是你的版本。比如简体中文正式版是EULAID:WX.4_PRO_RTL_CN,繁体中文正式版是WX.4_PRO_RTL_TW。其中:如果是WX.开头是正式版,WB.开头是测试版。_PRE,代表家庭版;_PRO,代表专业版。

α、β、λ常用来表示软件测试过程中的三个阶段,α是第一阶段,一般只供内部测试使用;β是第二个阶段,已经消除了软件中大部分的不完善之处,但仍有可能还存在缺陷和漏洞,一般只提供给特定的用户群来测试使用;λ是第三个阶段,此时产品已经相当成熟,只需在个别地方再做进一步的优化处理即可上市发行。

转载:

Alpha、Beta、RC、GA版本的区别

[ERROR] InnoDB: redo log file ‘./ib_logfile0’ exists

1
2
3
4
5
6
2020-07-31T01:24:43.755177Z 0 [ERROR] InnoDB: redo log file './ib_logfile0' exists. Creating system tablespace with existing redo log files is not recommended. Please delete all redo log files before creating new system tablespace.
2020-07-31T01:24:43.755184Z 0 [ERROR] InnoDB: InnoDB Database creation was aborted with error Generic error. You may need to delete the ibdata1 file before trying to start up again.
2020-07-31T01:24:44.355412Z 0 [ERROR] Plugin 'InnoDB' init function returned error.
2020-07-31T01:24:44.355420Z 0 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
2020-07-31T01:24:44.355425Z 0 [ERROR] Failed to initialize builtin plugins.
2020-07-31T01:24:44.355429Z 0 [ERROR] Aborting

问题解决如下

1.如果数据不重要或已经有备份,只需要恢复mysql启动 (已验证可用)

进入mysql目录,一般是:/usr/local/mysql/data
删除ib_logfile*
删除ibdata*
删除所有数据库物理目录(例如数据库为test_db,则执行rm -rf test_db)
重启动mysql
重新建立数据库或使用备份覆盖

2.如果数据很重要且没有备份

可以使用innodb_force_recovery参数,使mysqld跳过恢复步骤,启动mysqld,将数据导出然后重建数据库。

innodb_force_recovery 可以设置为1-6,大的数字包含前面所有数字的影响

(SRV_FORCE_IGNORE_CORRUPT):忽略检查到的corrupt页。

(SRV_FORCE_NO_BACKGROUND):阻止主线程的运行,如主线程需要执行full purge操作,会导致crash。

(SRV_FORCE_NO_TRX_UNDO):不执行事务回滚操作。

(SRV_FORCE_NO_IBUF_MERGE):不执行插入缓冲的合并操作。

(SRV_FORCE_NO_UNDO_LOG_SCAN):不查看重做日志,InnoDB存储引擎会将未提交的事务视为已提交。

(SRV_FORCE_NO_LOG_REDO):不执行前滚的操作。

在my.cnf(windows是my.ini)中加入
innodb_force_recovery = 6
innodb_purge_thread = 0(purge多线程参数)

重启mysql

这时只可以执行 select,create,drop 操作,但不能执行 insert,update,delete 操作
执行逻辑导出,导出需要的数据库

完成后将innodb_force_recovery=0,innodb_purge_threads=1,

然后重建数据库,最后把导出的数据重新导入。

参考:

[ERROR] InnoDB: Plugin initialization aborted with error Generic error几种报错

启动mysql报错The server quit without updating PID file!

1
2
3
4
5
# 强制卸载:
rpm -e --nodeps xxxxxx.rpm

# 强制安装:
rpm -ivh --nodeps xxxxxx.rpm

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
rpm -e --nodeps glib2

# 进入挂载的镜像内
cd /media/cdrom/
cd Packages/
ls | grep glib2

[root@host Packages]# ls | grep glib2
compat-libpackagekit-glib2-16-0.8.9-1.el7.x86_64.rpm
glib2-2.54.2-2.el7.x86_64.rpm
glib2-devel-2.54.2-2.el7.x86_64.rpm
pulseaudio-libs-glib2-10.0-5.el7.x86_64.rpm

[root@host Packages]# rpm -ivh glib2-2.54.2-2.el7.x86_64.rpm

1.编译的时候后缀带了.class:把后缀去掉;
2.删除java文件中的package包;(不推荐)
2.当java文件带了package包,但是还在java文件所在目录运行,这种情况会报错;

正确做法:返回包的前一目录进行运行;

正确示例:

1
2
PS E:\java\javademo\src> javac -encoding UTF-8 ServerSocketTest/GreetingServer.java
PS E:\java\javademo\src> java ServerSocketTest/GreetingServer

当Java源代码中包含中文字符时,我们在用javac编译时会出现“错误:编码GBK的不可映射字符”。

由于JDK是国际版的,我们在用javac编译时,编译程序首先会获得我们操作系统默认采用的编码格式(GBK),然后JDK就把Java源文件从GBK编码格式转换为Java内部默认的Unicode格式放入内存中,然后javac把转换后的Unicode格式的文件编译成class类文件,此时,class文件是Unicode编码的,它暂存在内存中,紧接着,JDK将此以Unicode格式编码的class文件保存到操作系统中形成我们见到的class文件。当我们不加设置就编译时,相当于使用了参数:javac -encoding GBK Test.java,就会出现不兼容的情况。

使用-encoding参数指明编码方式:javac -encoding UTF-8 Test.java,就可以了。

转载:错误:编码GBK的不可映射字符

打开环境变量窗口

右键 This PC(此电脑) -> Properties(属性) -> Advanced system settings(高级系统设置) -> Environment Variables(环境变量)

微信截图_20200716151758.png

微信截图_20200716151834.png

微信截图_20200716151910.png

新建JAVA_HOME 变量

1
2
变量名:JAVA_HOME
变量值:电脑上JDK安装的绝对路径

微信截图_20200716152023.png

新建/修改 CLASSPATH 变量

如果存在 CLASSPATH 变量,选中点击 Edit(编辑)。

如果没有,点击 New(新建)… 新建。

输入/在已有的变量值后面添加:

1
2
变量名:CLASSPATH
变量值:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;

微信截图_20200716152137.png

修改Path 变量

由于 win10 的不同,当选中 Path 变量的时候,系统会很方便的把所有不同路径都分开了,不会像 win7 或者 win8 那样连在一起。

微信截图_20200716152234.png

新建两条路径:

1
2
%JAVA_HOME%\bin
%JAVA_HOME%\jre\bin

验证

1
2
3
java
java -version
javac

参考:

Windows 10 配置Java 环境变量

转载:

IDEA最好用插件推荐

Alibaba Java Coding Guidelines

安装该插件后,代码超过 80 行、手动创建线程池等,这些和《手册》中的规约不符时,IDEA中会给出警告提示。

建议大家一定要安装该插件,它会帮助你检查出很多隐患,督促你写更规范的代码。

地址:Alibaba Java Coding Guidelines

jclasslib bytecode viewer

地址:jclasslib bytecode viewer

jclasslib:一款可视化的字节码查看插件。

大家可以直接在 IDEA 插件管理中安装(安装步骤略)。

使用方法:

1,在 IDEA 打开想研究的类。
2,编译该类或者直接编译整个项目( 如果想研究的类在 jar 包中,此步可略过)。
3,打开“view” 菜单,选择“Show Bytecode With jclasslib” 选项。
4,选择上述菜单项后 IDEA 中会弹出 jclasslib 工具窗口。

那么有自带的强大的反汇编工具 javap 还有必要用这个插件吗?

这个插件的强大之处在于:

不需要敲命令,简单直接,在右侧方便和源代码进行对比学习。
字节码命令支持超链接,点击其中的虚拟机指令即可跳转到 jvms 相关章节,超级方便。
该插件对我们学习虚拟机指令有极大的帮助。

具体可以参考:IDEA字节码学习查看神器介绍

Codota

支持智能代码自动提示,该功能可以增强 IDEA 的代码提示功能。
支持 JDK 和知名第三方库的函数的使用方法搜索,可以看到其他知名开源项目对该函数的用法。
当我们第一次使用某个类,对某个函数不够熟悉时,可以通过该插件搜索相关用法,快速模仿学习。
可以使用该插件查看知名开源项目的用法。插件窗口顶部还给出了该类最常用的函数,可以点击查看相关用法案例,每个案例右侧的 “view source”可以跳转到该片段对应的开源项目的源码中。

地址:Codota

Auto filling Java call arguments

开发中,我们通常会调用其他已经编写好的函数,调用后需要填充参数,但是绝大多数情况下,传入的变量名称和该函数的参数名一致,当参数较多时,手动单个填充参数非常浪费时间。

该插件就可以帮你解决这个问题。

安装完该插件以后,调用一个函数,使用 Alt+Enter 组合键,调出 “Auto fill call parameters” 自动使用该函数定义的参数名填充。

GenerateO2O、GenerateAllSette

我们定义好从 A 类转换到 B 类的函数转换函数后,使用这两个插件可以自动调用 Getter 和 Setter 函数实行自动转换。

实际开发中还有一个非常常见的场景: 我们创建一个对象后,想依次调用 Setter 函数对属性赋值,如果属性较多很容易遗漏或者重复。

可以使用这 GenerateAllSetter 提供的功能,自动调用所有 Setter 函数(可填充默认值),然后自己再跟进实际需求设置属性值。

Rainbow Brackets

由于很多人没有养成好的编码风格,没有随手 format 代码的习惯,甚至有些同事会写代码超过几百行,阅读起来将非常痛苦。

痛苦的原因之一就是找到上下文,由于括号太多,不确定当前代码行是否属于某个代码块,此时这个插件就会帮上大忙。

插件 github 地址:https://github.com/izhangzhihao/intellij-rainbow-brackets

Maven Helper

现在 Java 项目通常会使用 maven 或者 gradle 构建,对于maven 项目来说, jar 包冲突非常常见。

那么如何更容易地查看和解决 jar 包冲突呢?

大家可以安装该插件,安装后 IDEA 中打开 pom.xml 文件时,就会多出一个 “Dependency Analyzer” 选项卡。

如上图所示,该插件支持值插件冲突的 jar 包,可以选择冲突的 jar 包将其 exclude 掉。

FindBugs

FindBugs 作为静态代码检查插件,可以检查你代码中的隐患,并给出原因。

地址:FindBugs-IDEA

SequenceDiagram

SequenceDiagram 可以根据代码调用链路自动生成时序图,超级赞,超级推荐!

这对研究源码,梳理工作中的业务代码有极大的帮助,堪称神器。

安装完成后,在某个类的某个函数中,右键 –> Sequence Diagaram 即可调出。

如下图是 Netty 的源码,可以通过该插件绘制出当前函数的调用链路。

双击顶部的类名可以跳转到对应类的源码中,双击调用的函数名可以直接调入某个函数的源码,总之非常强大。

地址:SequenceDiagram

Stack trace to UML

Stack trace to UML 支持根据 JVM 异常堆栈画 UML时序图和通信图。

打开方式 Analyze > Open Stack trace to UML plugin + Generate UML diagrams from stacktrace from debug

地址:Stack trace to UML

Java Stream Debugger

Stream 非常好用,可以灵活对数据进行操作,但是对很多刚接触的人来说,不好理解。

那么 Java Stream Debugger 这款神器的 IDEA 就可以帮到你。它可以将 Stream 的操作步骤可视化,非常有助于我们的学习。

地址:Java Stream Debugger

JOL Java Object Layout

查看对象布局和大小的插件,非常赞。

地址:JOL Java Object Layout

转载:

Java格式化输出printf例子

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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import java.util.Date;

/**
* 使用printf输出
*/
/**关键技术点
* 使用java.io.PrintStream的printf方法实现C风格的输出
* printf 方法的第一个参数为输出的格式,第二个参数是可变长的,表示待输出的数据对象
*/
public class Printf {

public static void main(String[] args) {
/*** 输出字符串 ***/
// %s表示输出字符串,也就是将后面的字符串替换模式中的%s
System.out.printf("%s", new Integer(1212));
// %n表示换行
System.out.printf("%s%n", "end line");
// 还可以支持多个参数
System.out.printf("%s = %s%n", "Name", "Zhangsan");
// %S将字符串以大写形式输出
System.out.printf("%S = %s%n", "Name", "Zhangsan");
// 支持多个参数时,可以在%s之间插入变量编号,1$表示第一个字符串,3$表示第3个字符串
System.out.printf("%1$s = %3$s %2$s%n", "Name", "san", "Zhang");

/*** 输出boolean类型 ***/
System.out.printf("true = %b; false = ", true);
System.out.printf("%b%n", false);

/*** 输出整数类型***/
Integer iObj = 342;
// %d表示将整数格式化为10进制整数
System.out.printf("%d; %d; %d%n", -500, 2343L, iObj);
// %o表示将整数格式化为8进制整数
System.out.printf("%o; %o; %o%n", -500, 2343L, iObj);
// %x表示将整数格式化为16进制整数
System.out.printf("%x; %x; %x%n", -500, 2343L, iObj);
// %X表示将整数格式化为16进制整数,并且字母变成大写形式
System.out.printf("%X; %X; %X%n", -500, 2343L, iObj);

/*** 输出浮点类型***/
Double dObj = 45.6d;
// %e表示以科学技术法输出浮点数
System.out.printf("%e; %e; %e%n", -756.403f, 7464.232641d, dObj);
// %E表示以科学技术法输出浮点数,并且为大写形式
System.out.printf("%E; %E; %E%n", -756.403f, 7464.232641d, dObj);
// %f表示以十进制格式化输出浮点数
System.out.printf("%f; %f; %f%n", -756.403f, 7464.232641d, dObj);
// 还可以限制小数点后的位数
System.out.printf("%.1f; %.3f; %f%n", -756.403f, 7464.232641d, dObj);

/*** 输出日期类型***/
// %t表示格式化日期时间类型,%T是时间日期的大写形式,在%t之后用特定的字母表示不同的输出格式
Date date = new Date();
long dataL = date.getTime();
// 格式化年月日
// %t之后用y表示输出日期的年份(2位数的年,如99)
// %t之后用m表示输出日期的月份,%t之后用d表示输出日期的日号
System.out.printf("%1$ty-%1$tm-%1$td; %2$ty-%2$tm-%2$td%n", date, dataL);
// %t之后用Y表示输出日期的年份(4位数的年),
// %t之后用B表示输出日期的月份的完整名, %t之后用b表示输出日期的月份的简称
System.out.printf("%1$tY-%1$tB-%1$td; %2$tY-%2$tb-%2$td%n", date, dataL);

// 以下是常见的日期组合
// %t之后用D表示以 "%tm/%td/%ty"格式化日期
System.out.printf("%1$tD%n", date);
//%t之后用F表示以"%tY-%tm-%td"格式化日期
System.out.printf("%1$tF%n", date);

/*** 输出时间类型***/
// 输出时分秒
// %t之后用H表示输出时间的时(24进制),%t之后用I表示输出时间的时(12进制),
// %t之后用M表示输出时间的分,%t之后用S表示输出时间的秒
System.out.printf("%1$tH:%1$tM:%1$tS; %2$tI:%2$tM:%2$tS%n", date, dataL);
// %t之后用L表示输出时间的秒中的毫秒
System.out.printf("%1$tH:%1$tM:%1$tS %1$tL%n", date);
// %t之后p表示输出时间的上午或下午信息
System.out.printf("%1$tH:%1$tM:%1$tS %1$tL %1$tp%n", date);

// 以下是常见的时间组合
// %t之后用R表示以"%tH:%tM"格式化时间
System.out.printf("%1$tR%n", date);
// %t之后用T表示以"%tH:%tM:%tS"格式化时间
System.out.printf("%1$tT%n", date);
// %t之后用r表示以"%tI:%tM:%tS %Tp"格式化时间
System.out.printf("%1$tr%n", date);

/*** 输出星期***/
// %t之后用A表示得到星期几的全称
System.out.printf("%1$tF %1$tA%n", date);
// %t之后用a表示得到星期几的简称
System.out.printf("%1$tF %1$ta%n", date);

// 输出时间日期的完整信息
System.out.printf("%1$tc%n", date);
}
}
/**
*printf方法中,格式为"%s"表示以字符串的形式输出第二个可变长参数的第一个参数值;
*格式为"%n"表示换行;格式为"%S"表示将字符串以大写形式输出;在"%s"之间用"n$"表示
*输出可变长参数的第n个参数值.格式为"%b"表示以布尔值的形式输出第二个可变长参数
*的第一个参数值.
*/
/**
* 格式为"%d"表示以十进制整数形式输出;"%o"表示以八进制形式输出;"%x"表示以十六进制
* 输出;"%X"表示以十六进制输出,并且将字母(A、B、C、D、E、F)换成大写.格式为"%e"表
* 以科学计数法输出浮点数;格式为"%E"表示以科学计数法输出浮点数,而且将e大写;格式为
* "%f"表示以十进制浮点数输出,在"%f"之间加上".n"表示输出时保留小数点后面n位.
*/
/**
* 格式为"%t"表示输出时间日期类型."%t"之后用y表示输出日期的二位数的年份(如99)、用m
* 表示输出日期的月份,用d表示输出日期的日号;"%t"之后用Y表示输出日期的四位数的年份
* (如1999)、用B表示输出日期的月份的完整名,用b表示输出日期的月份的简称."%t"之后用D
* 表示以"%tm/%td/%ty"的格式输出日期、用F表示以"%tY-%tm-%td"的格式输出日期.
*/
/**
* "%t"之后用H表示输出时间的时(24进制),用I表示输出时间的时(12进制),用M表示输出时间
* 分,用S表示输出时间的秒,用L表示输出时间的秒中的毫秒数、用 p 表示输出时间的是上午还是
* 下午."%t"之后用R表示以"%tH:%tM"的格式输出时间、用T表示以"%tH:%tM:%tS"的格式输出
* 时间、用r表示以"%tI:%tM:%tS %Tp"的格式输出时间.
*/
/**
* "%t"之后用A表示输出日期的全称,用a表示输出日期的星期简称.
*/

Ctrl+Alt+L:格式化代码;

Ctrl+Q:查询引用;

Alt+Enter:导入包;

F4:查看源码;

Ctrl+Alt+B:导航到抽象方法的实现;

F7:在 Debug 模式下,进入下一步,如果当前行断点是一个方法,则进入当前方法体内,如果该方法体还有方法,则不会进入该内嵌的方法中

F8:在 Debug 模式下,进入下一步,如果当前行断点是一个方法,则不进入当前方法体内

F9:在 Debug 模式下,恢复程序运行,但是如果该断点下面代码还有断点则停在下一个断点上

F12:回到前一个工具窗口

Ctrl + / :行注释,再次使用,去掉行注释

**Ctrl + Shift + /**:块注释

输入/** :方法注释,点击 Enter,自动根据参数和返回值生成注释模板

https://github.com/judasn/IntelliJ-IDEA-Tutorial/blob/master/keymap-introduce.md

NPM常用命令

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
# 查看版本
npm -v

# 查看安装的包
npm list
npm -global list

# 查看某个模块的全部信息
npm info name

# 查看单个信息
npm info name version
npm info name homepage

# install支持多种手段,包名,git路径,包括本地路径
# 注:离线安装存在包依赖,可能会出错
sudo npm install -global [package name]
npm install git://github.com/package/path.git
npm install git://github.com/package/path.git#0.1.0
npm install package_name@version
npm install path/to/somedir //本地路径

# 清除缓存
npm cache clean

# 查看配置项
npm config list
npm config list -l

参考

npm用法及离线安装方法

联网机器安装NPM包

http-server 为例:

1
2
3
4
5
6
7
8
9
# 首先查看 node npm 版本
C:\Users\DELL>npm -v
6.13.4

C:\Users\DELL>node -v
v12.16.1

# 安装 http-server
npm install http-server -g
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 查看配置,找到安装目录
npm config list

C:\Users\DELL>npm config list
; cli configs
metrics-registry = "https://registry.npmjs.org/"
scope = ""
user-agent = "npm/6.13.4 node/v12.16.1 win32 x64"

; builtin config undefined
prefix = "C:\\Users\\DELL\\AppData\\Roaming\\npm"

; node bin location = C:\Program Files\nodejs\node.exe
; cwd = C:\Users\DELL
; HOME = C:\Users\DELL
; "npm config ls -l" to show all defaults.

查看 C:\\Users\\DELL\\AppData\\Roaming\\npm 目录,截图如下:

npm-path.png
npm-http-server

通过ftp工具拷贝到未联网服务器

1
2
3
4
# 本地文件夹:C:\\Users\\DELL\\AppData\\Roaming\\npm 下的文件,
# 拷贝到 服务器上 /root/.npm 下 (不存在,使用mkdir命令创建)
http-server
http-server.cmd

如图:

微信截图_20200520102421.png

1
2
3
# 本地文件夹:C:\Users\DELL\AppData\Roaming\npm\node_modules 下的文件夹,
# 拷贝到 服务器上 /root/.npm/node_modules 下
http-server

如图:

微信截图_20200520102513.png

安装启动

1
2
3
4
5
6
7
8
9
10
11
12
# 安装
npm install /root/.npm/node_modules/http-server -g

# 启动
http-server /test/webapp -p 8013

# 查看监听的端口
netstat -lnpt

# curl 命令验证
curl -o /dev/null -s -w %{http_code} -X GET "192.125.30.82:8013/pages/tsjb/lzsp.html" -H "accept: text/html"
curl -X GET "192.125.30.82:8013/pages/tsjb/lzsp.html" -H "accept: text/html"

参考:

https://stackoverflow.com/questions/43064107/how-to-install-npm-package-while-offline/58744517#58744517

npm install

npm 模块安装机制简介

NPM离线包

npmbox