0%

基本操作

Linux关机,重启

script
1
2
3
4
5
# 关机
shutdown -h now

# 重启
shutdown -r now

查看系统,CPU信息

script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 查看系统内核信息
uname -a

# 查看系统内核版本
cat /proc/version

# 查看当前用户环境变量
env

cat /proc/cpuinfo

# 查看有几个逻辑cpu, 包括cpu型号
cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c

# 查看有几颗cpu,每颗分别是几核
cat /proc/cpuinfo | grep physical | uniq -c

# 查看当前CPU运行在32bit还是64bit模式下, 如果是运行在32bit下也不代表CPU不支持64bit
getconf LONG_BIT

# 结果大于0, 说明支持64bit计算. lm指long mode, 支持lm则是64bit
cat /proc/cpuinfo | grep flags | grep ' lm ' | wc -l

建立软连接

script
1
ln -s /usr/local/jdk1.8/ jdk

rpm相关

script
1
2
# 查看是否通过rpm安装了该软件
rpm -qa | grep 软件名

sshkey

script
1
2
3
4
5
# 创建sshkey
ssh-keygen -t rsa -C your_email@example.com

#id_rsa.pub 的内容拷贝到要控制的服务器的 home/username/.ssh/authorized_keys 中,
# 如果没有则新建(.ssh权限为700, authorized_keys权限为600)

命令重命名

script
1
2
# 在各个用户的.bash_profile中添加重命名配置
alias ll='ls -alF'

同步服务器时间

script
1
sudo ntpdate -u ntp.api.bz

后台运行命令

script
1
2
3
4
5
6
7
8
# 后台运行,并且有nohup.out输出
nohup xxx &

# 后台运行, 不输出任何日志
nohup xxx > /dev/null &

# 后台运行, 并将错误信息做标准输出到日志中
nohup xxx >out.log 2>&1 &

强制活动用户退出

script
1
2
# 命令来完成强制活动用户退出.其中TTY表示终端名称
pkill -kill -t [TTY]

查看命令路径

script
1
which <命令>

查看进程所有打开最大fd数

script
1
ulimit -n

配置dns

script
1
vim /etc/resolv.conf

nslookup,查看域名路由表

script
1
nslookup google.com

last, 最近登录信息列表

script
1
2
# 最近登录的5个账号
last -n 5

设置固定ip

script
1
ifconfig em1  192.168.5.177 netmask 255.255.255.0

查看进程内加载的环境变量

script
1
2
# 也可以去 cd /proc 目录下, 查看进程内存中加载的东西
ps eww -p XXXXX(进程号)

查看进程树找到服务器进程

script
1
ps auwxf

查看进程启动路径

script
1
2
3
cd /proc/xxx(进程号)
ls -all
# cwd对应的是启动路径

添加用户, 配置sudo权限

script
1
2
3
4
5
6
7
8
9
# 新增用户
useradd 用户名
passwd 用户名

#增加sudo权限
vim /etc/sudoers
# 修改文件里面的
# root ALL=(ALL) ALL
# 用户名 ALL=(ALL) ALL

强制关闭进程名包含xxx的所有进程

script
1
ps aux|grep xxx | grep -v grep | awk '{print $2}' | xargs kill -9

磁盘,文件,目录相关操作

vim操作

script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#normal模式下 g表示全局, x表示查找的内容, y表示替换后的内容
:%s/x/y/g

#normal模式下
0 # 光标移到行首(数字0)
$ # 光标移至行尾
shift + g # 跳到文件最后
gg # 跳到文件头

# 显示行号
:set nu

# 去除行号
:set nonu

# 检索
/xxx(检索内容) # 从头检索, 按n查找下一个
?xxx(检索内容) # 从尾部检索

打开只读文件,修改后需要保存时(不用切换用户即可保存的方式)

script
1
2
# 在normal模式下
:w !sudo tee %

查看磁盘, 文件目录基本信息

script
1
2
3
4
5
6
7
8
9
10
11
# 查看磁盘挂载情况
mount

# 查看磁盘分区信息
df

# 查看目录及子目录大小
du -H -h

# 查看当前目录下各个文件, 文件夹占了多少空间, 不会递归
du -sh *

wc命令

script
1
2
3
4
5
6
7
8
9
10
11
# 查看文件里有多少行
wc -l filename

# 看文件里有多少个word
wc -w filename

# 文件里最长的那一行是多少个字
wc -L filename

# 统计字节数
wc -c

常用压缩, 解压缩命令

压缩命令

script
1
2
3
tar czvf xxx.tar 压缩目录

zip -r xxx.zip 压缩目录

解压缩命令

script
1
2
3
4
5
6
tar zxvf xxx.tar

# 解压到指定文件夹
tar zxvf xxx.tar -C /xxx/yyy/

unzip xxx.zip

变更文件所属用户, 用户组

script
1
chown eagleye.eagleye xxx.log

cp, scp, mkdir

script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#复制
cp xxx.log

# 复制并强制覆盖同名文件
cp -f xxx.log

# 复制文件夹
cp -r xxx(源文件夹) yyy(目标文件夹)

# 远程复制
scp -P ssh端口 username@10.10.10.101:/home/username/xxx /home/xxx

# 级联创建目录
mkdir -p /xxx/yyy/zzz

# 批量创建文件夹, 会在test,main下都创建java, resources文件夹
mkdir -p src/{test,main}/{java,resources}

比较两个文件

script
1
diff -u 1.txt 2.txt

日志输出的字节数,可以用作性能测试

script
1
2
# 如果做性能测试, 可以每执行一次, 往日志里面输出 “.” , 这样日志中的字节数就是实际的性能测试运行的次数, 还可以看见实时速率.
tail -f xxx.log | pv -bt

查看, 去除特殊字符

script
1
2
3
4
5
# 查看特殊字符
cat -v xxx.sh

# 去除特殊字符
sed -i 's/^M//g’ env.sh 去除文件的特殊字符, 比如^M: 需要这样输入: ctrl+v+enter

处理因系统原因引起的文件中特殊字符的问题

script
1
2
3
4
5
6
7
8
9
10
11
12
# 可以转换为该系统下的文件格式
cat file.sh > file.sh_bak

# 先将file.sh中文件内容复制下来然后运行, 然后粘贴内容, 最后ctrl + d 保存退出
cat > file1.sh

# 在vim中通过如下设置文件编码和文件格式
:set fileencodings=utf-8 ,然后 w (存盘)一下即可转化为 utf8 格式,
:set fileformat=unix

# 在mac下使用dos2unix进行文件格式化
find . -name "*.sh" | xargs dos2unix

tee, 重定向的同时输出到屏幕

script
1
awk '{print $0}' xxx.log | tee test.log

检索相关

grep

script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 反向匹配, 查找不包含xxx的内容
grep -v xxx

# 排除所有空行
grep -v '^/pre>'

# 返回结果 2,则说明第二行是空行
grep -n "^$" 111.txt

# 查询以abc开头的行
grep -n '^abc' 111.txt

# 同时列出该词语出现在文章的第几行
grep 'xxx' -n xxx.log

# 计算一下该字串出现的次数
grep 'xxx' -c xxx.log

# 比对的时候,不计较大小写的不同
grep 'xxx' -i xxx.log

awk

script
1
2
3
4
5
#':' 为分隔符,如果第五域有user则输出该行
awk -F ':' '{if ($5 ~ /user/) print $0}' /etc/passwd

# 统计单个文件中某个字符(串)(中文无效)出现的次数
awk -v RS='character' 'END {print --NR}' xxx.txt

find检索命令

script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 在目录下找后缀是.mysql的文件
find /home/eagleye -name '*.mysql' -print

# 会从 /usr 目录开始往下找,找最近3天之内存取过的文件。
find /usr -atime 3 –print

# 会从 /usr 目录开始往下找,找最近5天之内修改过的文件。
find /usr -ctime 5 –print

# 会从 /doc 目录开始往下找,找jacky 的、文件名开头是 j的文件。
find /doc -user jacky -name 'j*' –print

# 会从 /doc 目录开始往下找,找寻文件名是 ja 开头或者 ma开头的文件。
find /doc \( -name 'ja*' -o- -name 'ma*' \) –print

# 会从 /doc 目录开始往下找,找到凡是文件名结尾为 bak的文件,把它删除掉。-exec 选项是执行的意思,rm 是删除命令,{ } 表示文件名,“\;”是规定的命令结尾。
find /doc -name '*bak' -exec rm {} \;

网络相关

查看什么进程使用了该端口

script
1
lsof -i:port

获取本机ip地址

script
1
2
ifconfig
/sbin/ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $2}'|tr -d "addr:"

iptables

script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 查看iptables状态
service iptables status

# 要封停一个ip
iptables -I INPUT -s ***.***.***.*** -j DROP

# 要解封一个IP,使用下面这条命令:
iptables -D INPUT -s ***.***.***.*** -j DROP

#备注: 参数-I是表示Insert(添加),-D表示Delete(删除)。后面跟的是规则,INPUT表示入站,***.***.***.***表示要封停的IP,DROP表示放弃连接。

#开启9090端口的访问
/sbin/iptables -I INPUT -p tcp --dport 9090 -j ACCEPT

# 防火墙开启、关闭、重启
/etc/init.d/iptables status
/etc/init.d/iptables start
/etc/init.d/iptables stop
/etc/init.d/iptables restart

nc命令, tcp调试利器

script
1
2
3
4
5
6
7
8
#给某一个endpoint发送TCP请求,就将data的内容发送到对端
nc 192.168.0.11 8000 < data.txt

#nc可以当做服务器,监听某个端口号,把某一次请求的内容存储到received_data里
nc -l 8000 > received_data

#上边只监听一次,如果多次可以加上-k参数
nc -lk 8000

tcpdump

script
1
2
# dump出本机12301端口的tcp包
tcpdump -i em1 tcp port 12301 -s 1500 -w abc.pcap

跟踪网络路由路径

script
1
2
3
4
5
6
7
8
# traceroute默认使用udp方式, 如果是-I则改成icmp方式
traceroute -I www.163.com

# 从ttl第3跳跟踪
traceroute -M 3 www.163.com

# 加上端口跟踪
traceroute -p 8080 192.168.10.11

ss

script
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
# 显示本地打开的所有端口
ss -l

# 显示每个进程具体打开的socket
ss -pl

# 显示所有tcp socket
ss -t -a

# 显示所有的UDP Socekt
ss -u -a

# 显示所有已建立的SMTP连接
ss -o state established '( dport = :smtp or sport = :smtp )'

# 显示所有已建立的HTTP连接
ss -o state established '( dport = :http or sport = :http )'

找出所有连接X服务器的进程
ss -x src /tmp/.X11-unix/*

列出当前socket统计信息
ss -s

#解释:netstat是遍历/proc下面每个PID目录,ss直接读/proc/net下面的统计信息。所以ss执行的时候消耗资源以及消耗的时间都比netstat少很多

netstat

script
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 输出每个ip的连接数,以及总的各个状态的连接数
netstat -n | awk '/^tcp/ {n=split($(NF-1),array,":");if(n<=2)++S[array[(1)]];else++S[array[(4)]];++s[$NF];++N} END {for(a in S){printf("%-20s %s\n", a, S[a]);++I}printf("%-20s %s\n","TOTAL_IP",I);for(a in s) printf("%-20s %s\n",a, s[a]);printf("%-20s %s\n","TOTAL_LINK",N);}'

# 统计所有连接状态,
# CLOSED:无连接是活动的或正在进行
# LISTEN:服务器在等待进入呼叫
# SYN_RECV:一个连接请求已经到达,等待确认
# SYN_SENT:应用已经开始,打开一个连接
# ESTABLISHED:正常数据传输状态
# FIN_WAIT1:应用说它已经完成
# FIN_WAIT2:另一边已同意释放
# ITMED_WAIT:等待所有分组死掉
# CLOSING:两边同时尝试关闭
# TIME_WAIT:主动关闭连接一端还没有等到另一端反馈期间的状态
# LAST_ACK:等待所有分组死掉
netstat -n | awk '/^tcp/ {++state[$NF]} END {for(key in state) print key,"\t",state[key]}'

# 查找较多time_wait连接
netstat -n|grep TIME_WAIT|awk '{print $5}'|sort|uniq -c|sort -rn|head -n20

监控linux性能命令

top

按大写的 F 或 O 键,然后按 a-z 可以将进程按照相应的列进行排序, 然后回车。而大写的 R 键可以将当前的排序倒转

列名 含义
PID 进程id
PPID 父进程id
RUSER Real user name
UID 进程所有者的用户id
USER 进程所有者的用户名
GROUP 进程所有者的组名
TTY 启动进程的终端名。不是从终端启动的进程则显示为 ?
PR 优先级
NI nice值。负值表示高优先级,正值表示低优先级
P 最后使用的CPU,仅在多CPU环境下有意义
%CPU 上次更新到现在的CPU时间占用百分比
TIME 进程使用的CPU时间总计,单位秒
TIME+ 进程使用的CPU时间总计,单位1/100秒
%MEM 进程使用的物理内存百分比
VIRT 进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES
SWAP 进程使用的虚拟内存中,被换出的大小,单位kb。
RES 进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA
CODE 可执行代码占用的物理内存大小,单位kb
DATA 可执行代码以外的部分(数据段+栈)占用的物理内存大小,单位kb
SHR 共享内存大小,单位kb
nFLT 页面错误次数
nDRT 最后一次写入到现在,被修改过的页面数。
S 进程状态。D=不可中断的睡眠状态,R=运行,S=睡眠,T=跟踪/停止,Z=僵尸进程
COMMAND 命令名/命令行
WCHAN 若该进程在睡眠,则显示睡眠中的系统函数名
Flags 任务标志,参考 sched.h

dmesg,查看系统日志

script
1
dmesg

iostat,磁盘IO情况监控

script
1
2
3
4
5
6
7
iostat -xz 1

# r/s, w/s, rkB/s, wkB/s:分别表示每秒读写次数和每秒读写数据量(千字节)。读写量过大,可能会引起性能问题。
# await:IO操作的平均等待时间,单位是毫秒。这是应用程序在和磁盘交互时,需要消耗的时间,包括IO等待和实际操作的耗时。如果这个数值过大,可能是硬件设备遇到了瓶颈或者出现故障。
# avgqu-sz:向设备发出的请求平均数量。如果这个数值大于1,可能是硬件设备已经饱和(部分前端硬件设备支持并行写入)。
# %util:设备利用率。这个数值表示设备的繁忙程度,经验值是如果超过60,可能会影响IO性能(可以参照IO操作平均等待时间)。如果到达100%,说明硬件设备已经饱和。
# 如果显示的是逻辑设备的数据,那么设备利用率不代表后端实际的硬件设备已经饱和。值得注意的是,即使IO性能不理想,也不一定意味这应用程序性能会不好,可以利用诸如预读取、写缓存等策略提升应用性能。

free,内存使用情况

script
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
free -m

eg:

total used free shared buffers cached
Mem: 1002 769 232 0 62 421
-/+ buffers/cache: 286 715
Swap: 1153 0 1153

#第一部分Mem行:
#total 内存总数: 1002M
#used 已经使用的内存数: 769M
#free 空闲的内存数: 232M
#shared 当前已经废弃不用,总是0
#buffers Buffer 缓存内存数: 62M
#cached Page 缓存内存数:421M

#关系:total(1002M) = used(769M) + free(232M)

#第二部分(-/+ buffers/cache):
#(-buffers/cache) used内存数:286M (指的第一部分Mem行中的used – buffers – cached)
#(+buffers/cache) free内存数: 715M (指的第一部分Mem行中的free + buffers + cached)

#可见-buffers/cache反映的是被程序实实在在吃掉的内存,而+buffers/cache反映的是可以挪用的内存总数.

#第三部分是指交换分区

sar,查看网络吞吐状态

script
1
2
3
4
5
6
7
8
9
10
# sar命令在这里可以查看网络设备的吞吐率。在排查性能问题时,可以通过网络设备的吞吐量,判断网络设备是否已经饱和
sar -n DEV 1

#
# sar命令在这里用于查看TCP连接状态,其中包括:
# active/s:每秒本地发起的TCP连接数,既通过connect调用创建的TCP连接;
# passive/s:每秒远程发起的TCP连接数,即通过accept调用创建的TCP连接;
# retrans/s:每秒TCP重传数量;
# TCP连接数可以用来判断性能问题是否由于建立了过多的连接,进一步可以判断是主动发起的连接,还是被动接受的连接。TCP重传可能是因为网络环境恶劣,或者服务器压力过大导致丢包
sar -n TCP,ETCP 1

vmstat, 给定时间监控CPU使用率, 内存使用, 虚拟内存交互, IO读写

script
1
2
3
4
5
6
7
8
9
10
# 2表示每2秒采集一次状态信息, 1表示只采集一次(忽略既是一直采集)
vmstat 2 1

eg:
r b swpd free buff cache si so bi bo in cs us sy id wa
1 0 0 3499840 315836 3819660 0 0 0 1 2 0 0 0 100 0
0 0 0 3499584 315836 3819660 0 0 0 0 88 158 0 0 100 0
0 0 0 3499708 315836 3819660 0 0 0 2 86 162 0 0 100 0
0 0 0 3499708 315836 3819660 0 0 0 10 81 151 0 0 100 0
1 0 0 3499732 315836 3819660 0 0 0 2 83 154 0 0 100 0
  • r 表示运行队列(就是说多少个进程真的分配到CPU),我测试的服务器目前CPU比较空闲,没什么程序在跑,当这个值超过了CPU数目,就会出现CPU瓶颈了。这个也和top的负载有关系,一般负载超过了3就比较高,超过了5就高,超过了10就不正常了,服务器的状态很危险。top的负载类似每秒的运行队列。如果运行队列过大,表示你的CPU很繁忙,一般会造成CPU使用率很高。
  • b 表示阻塞的进程,这个不多说,进程阻塞,大家懂的。
  • swpd 虚拟内存已使用的大小,如果大于0,表示你的机器物理内存不足了,如果不是程序内存泄露的原因,那么你该升级内存了或者把耗内存的任务迁移到其他机器。
  • free 空闲的物理内存的大小,我的机器内存总共8G,剩余3415M。
  • buff Linux/Unix系统是用来存储,目录里面有什么内容,权限等的缓存,我本机大概占用300多M
  • cache cache直接用来记忆我们打开的文件,给文件做缓冲,我本机大概占用300多M(这里是Linux/Unix的聪明之处,把空闲的物理内存的一部分拿来做文件和目录的缓存,是为了提高 程序执行的性能,当程序使用内存时,buffer/cached会很快地被使用。)
  • si 每秒从磁盘读入虚拟内存的大小,如果这个值大于0,表示物理内存不够用或者内存泄露了,要查找耗内存进程解决掉。我的机器内存充裕,一切正常。
  • so 每秒虚拟内存写入磁盘的大小,如果这个值大于0,同上。
  • bi 块设备每秒接收的块数量,这里的块设备是指系统上所有的磁盘和其他块设备,默认块大小是1024byte,我本机上没什么IO操作,所以一直是0,但是我曾在处理拷贝大量数据(2-3T)的机器上看过可以达到140000/s,磁盘写入速度差不多140M每秒
  • bo 块设备每秒发送的块数量,例如我们读取文件,bo就要大于0。bi和bo一般都要接近0,不然就是IO过于频繁,需要调整。
  • in 每秒CPU的中断次数,包括时间中断
  • cs 每秒上下文切换次数,例如我们调用系统函数,就要进行上下文切换,线程的切换,也要进程上下文切换,这个值要越小越好,太大了,要考虑调低线程或者进程的数目,例如在apache和nginx这种web服务器中,我们一般做性能测试时会进行几千并发甚至几万并发的测试,选择web服务器的进程可以由进程或者线程的峰值一直下调,压测,直到cs到一个比较小的值,这个进程和线程数就是比较合适的值了。系统调用也是,每次调用系统函数,我们的代码就会进入内核空间,导致上下文切换,这个是很耗资源,也要尽量避免频繁调用系统函数。上下文切换次数过多表示你的CPU大部分浪费在上下文切换,导致CPU干正经事的时间少了,CPU没有充分利用,是不可取的。
  • us 用户CPU时间,我曾经在一个做加密解密很频繁的服务器上,可以看到us接近100,r运行队列达到80(机器在做压力测试,性能表现不佳)。
  • sy 系统CPU时间,如果太高,表示系统调用时间长,例如是IO操作频繁。
  • id 空闲 CPU时间,一般来说,id + us + sy = 100,一般我认为id是空闲CPU使用率,us是用户CPU使用率,sy是系统CPU使用率。
  • wt 等待IO CPU时间。

什么是jstat

Jstat是JDK自带的一个轻量级小工具。全称“Java Virtual Machine statistics monitoring tool”。
它位于java的bin目录下,主要利用JVM内建的指令对Java应用程序的资源和性能进行实时的命令行的监控,包括了对Heap size和垃圾回收状况的监控。
可见,Jstat是轻量级的、专门针对JVM的工具,非常适用。

jstat 命令相关参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
jstat命令命令格式:
jstat [Options] vmid [interval] [count]

命令参数说明:
Options,一般使用 -gcutil 或 -gc 查看gc 情况
pid,当前运行的 java进程号
interval,间隔时间,单位为秒或者毫秒
count,打印次数,如果缺省则打印无数次

Options 参数如下:
-gc:统计 jdk gc时 heap信息,以使用空间字节数表示
-gcutil:统计 gc时, heap情况,以使用空间的百分比表示
-class:统计 class loader行为信息
-compile:统计编译行为信息
-gccapacity:统计不同 generations(新生代,老年代,持久代)的 heap容量情况
-gccause:统计引起 gc的事件
-gcnew:统计 gc时,新生代的情况
-gcnewcapacity:统计 gc时,新生代 heap容量
-gcold:统计 gc时,老年代的情况
-gcoldcapacity:统计 gc时,老年代 heap容量
-gcpermcapacity:统计 gc时, permanent区 heap容量
-printcompilation (HotSpot编译统计)

-gc(GC堆状态)

示例:jstat -gc 1601 5000 3
说明:每5秒一次 打印3次 显示进程号为1601的 java进成的 GC情况,结果如下图

script
1
2
3
4
5
6
[root@iZ94sbzk035Z ~]# jstat -gc 1601 5000 3
S0C S1C S0U S1U EC EU OC OU MC MU CCSC CCSU YGC YGCT FGC FGCT GCT
1216.0 1216.0 188.7 0.0 9920.0 3300.8 12292.0 8239.6 24960.0 20411.5 5248.0 2736.0 22062 44.128 3 0.147 44.275
1216.0 1216.0 188.7 0.0 9920.0 3499.5 12292.0 8239.6 24960.0 20411.5 5248.0 2736.0 22062 44.128 3 0.147 44.275
1216.0 1216.0 188.7 0.0 9920.0 3500.9 12292.0 8239.6 24960.0 20411.5 5248.0 2736.0 22062 44.128 3 0.147 44.275

参数说明

显示列名 具体描述
S0C 年轻代中第一个survivor(幸存区)的容量 (KB)
S1C 年轻代中第二个survivor(幸存区)的容量 (KB)
S0U 年轻代中第一个survivor(幸存区)目前已使用空间 (KB)
S1U 年轻代中第二个survivor(幸存区)目前已使用空间 (KB)
EC 年轻代中Eden(伊甸园)的容量 (KB)
EU 年轻代中Eden(伊甸园)目前已使用空间 (KB)
OC 老年代大小(KB)
OU 老年代目前使用大小(KB)
MC 方法区大小
MU 方法区使用大小
CCSC 压缩类空间大小
CCSU 压缩类空间使用大小
YGC 年轻代垃圾回收次数:从应用程序启动到采样时年轻代中gc次数
YGCT 年轻代垃圾回收消耗时间:从应用程序启动到采样时年轻代中gc所用时间(s)
FGC 老年代垃圾回收次数:从应用程序启动到采样时old代(全gc)gc次数
FGCT 老年代垃圾回收消耗时间:从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT 垃圾回收消耗总时间:从应用程序启动到采样时gc用的总时间(s)

-gcutil (GC统计汇总)

示例:jstat -gcutil 1601 5000 3
说明:每5秒一次 打印3次 显示进程号为1601的 java进程垃圾回收统计情况,结果如下图

script
1
2
3
4
5
6
[root@iZ94sbzk035Z ~]# jstat -gcutil 1601 5000 3
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
28.03 0.00 34.41 67.03 81.78 52.14 22064 44.131 3 0.147 44.278
28.03 0.00 34.43 67.03 81.78 52.14 22064 44.131 3 0.147 44.278
28.03 0.00 36.41 67.03 81.78 52.14 22064 44.131 3 0.147 44.278

参数说明:

显示列名 具体描述
S0 年轻代中第一个survivor(幸存区)的容量 (KB)
S1 年轻代中第二个survivor(幸存区)的容量 (KB)
E 伊甸园区使用比例
O 老年代使用比例
M 元数据区使用比例
CCS 压缩使用比例
YGC 年轻代垃圾回收次数
YGCT 从应用程序启动到采样时年轻代中gc所用时间(s)
FGC 老年代垃圾回收次数
FGCT 老年代垃圾回收消耗时间
GCT 垃圾回收消耗总时间

-class(类加载器)

示例:每5秒一次 打印3次 显示进程号为1601的加载class的数量,及所占空间等信息

script
1
2
3
4
5
6
[root@iZ94sbzk035Z ~]# jstat -class 1601 5000 3
Loaded Bytes Unloaded Bytes Time
6615 11426.1 2417 3735.7 6.31
6615 11426.1 2417 3735.7 6.31
6615 11426.1 2417 3735.7 6.31

参数说明:

显示列名 具体描述
Loaded 装载的类的数量
Bytes 装载类所占用的字节数
Unloaded 卸载类的数量
Bytes 卸载类的字节数
Time 装载和卸载类所花费的时间

-compiler (JIT,统计编译行为信息)

示例:每5秒一次 打印3次 显示进程号为1601的显示JVM实时编译的数量等信息

script
1
2
3
4
5
6

[root@iZ94sbzk035Z ~]# jstat -compiler 1601 5000 3
Compiled Failed Invalid Time FailedType FailedMethod
- - - - - -
- - - - - -
- - - - - -

参数说明:

显示列名 具体描述
Compiled 编译任务执行数量
Failed 编译任务执行失败数量
Invalid 编译任务执行失效数量
Time 编译任务消耗时间
FailedType 最后一个编译失败任务的类型
FailedMethod 最后一个编译失败任务所在的类及方法

-gccapacity (各区大小)

统计不同 generations(新生代,老年代,持久代)的 heap容量情况

示例:每5秒一次 打印3次 显示进程号为1601的显示JVM内存中三代(young,old,perm)对象的使用和占用大小

script
1
2
3
4
5
6
[root@iZ94sbzk035Z ~]# jstat -gccapacity  1601 5000 3
NGCMN NGCMX NGC S0C S1C EC OGCMN OGCMX OGC OC MCMN MCMX MC CCSMN CCSMX CCSC YGC FGC
8192.0 16384.0 12352.0 1216.0 1216.0 9920.0 8192.0 16384.0 12292.0 12292.0 0.0 1069056.0 24960.0 0.0 1048576.0 5248.0 22082 3
8192.0 16384.0 12352.0 1216.0 1216.0 9920.0 8192.0 16384.0 12292.0 12292.0 0.0 1069056.0 24960.0 0.0 1048576.0 5248.0 22082 3
8192.0 16384.0 12352.0 1216.0 1216.0 9920.0 8192.0 16384.0 12292.0 12292.0 0.0 1069056.0 24960.0 0.0 1048576.0 5248.0 22082 3

参数说明:

显示列名 具体描述
NGCMN 年轻代(young)中初始化(最小)的大小(KB)
NGCMX 年轻代(young)的最大容量 (KB)
NGC 年轻代(young)中当前的容量 (KB)
S0C 年轻代中第一个survivor(幸存区)的容量 (KB)
S1C 年轻代中第二个survivor(幸存区)的容量 (KB)
EC 年轻代中Eden(伊甸园)的容量 (KB)
OGCMN old代中初始化(最小)的大小 (KB)
OGCMX old代的最大容量(KB)
OGC old代当前新生成的容量 (KB)
OC Old代的容量 (KB)
YGC 从应用程序启动到采样时年轻代中gc次数
FGC 从应用程序启动到采样时old代(全gc)gc次数

-gccause(统计引起 gc的事件)

示例:每5秒一次 打印3次 显示进程号为1601统计引起 gc的事件

script
1
2
3
4
5
[root@iZ94sbzk035Z ~]# jstat -gccause  1601 5000 3
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT LGCC GCC
22.08 0.00 97.71 67.04 81.78 52.14 22088 44.176 3 0.147 44.323 Allocation Failure No GC
22.08 0.00 97.75 67.04 81.78 52.14 22088 44.176 3 0.147 44.323 Allocation Failure No GC
22.08 0.00 100.00 67.04 81.78 52.14 22088 44.176 3 0.147 44.323 Allocation Failure No GC

参数说明:

显示列名 具体描述

-gcnew:(统计新生代的情况)

示例:每5秒一次 打印3次 显示进程号为1601的显示JVM内存中三代(young,old,perm)对象的使用和占用大小

script
1
2
3
4
5
[root@iZ94sbzk035Z ~]# jstat -gcnew 1601 5000 3
S0C S1C S0U S1U TT MTT DSS EC EU YGC YGCT
1216.0 1216.0 0.0 276.7 15 15 608.0 9920.0 8430.5 22089 44.178
1216.0 1216.0 0.0 276.7 15 15 608.0 9920.0 9491.0 22089 44.178
1216.0 1216.0 0.0 276.7 15 15 608.0 9920.0 9492.5 22089 44.178

参数说明:

显示列名 具体描述
S0C 年轻代中第一个survivor(幸存区)的容量 (KB)
S1C 年轻代中第二个survivor(幸存区)的容量 (KB)
S0U 年轻代中第一个survivor(幸存区)目前已使用空间 (KB)
S1U 年轻代中第二个survivor(幸存区)目前已使用空间 (KB)
TT 持有次数限制
MTT 最大持有次数限制
DSS
EC 年轻代中Eden(伊甸园)的容量 (KB)
EU 年轻代中Eden(伊甸园)目前已使用空间 (KB)
YGC 从应用程序启动到采样时年轻代中gc次数
YGCT 从应用程序启动到采样时年轻代中gc所用时间(s)

-gcnewcapacity(统计新生代 heap容量)

示例:每5秒一次 打印3次 显示进程号为1601的显示年轻代对象的信息及其占用量

script
1
2
3
4
5
6
[root@iZ94sbzk035Z ~]# jstat -gcnewcapacity 1601 5000 3
NGCMN NGCMX NGC S0CMX S0C S1CMX S1C ECMX EC YGC FGC
8192.0 16384.0 12352.0 1600.0 1216.0 1600.0 1216.0 13184.0 9920.0 22119 3
8192.0 16384.0 12352.0 1600.0 1216.0 1600.0 1216.0 13184.0 9920.0 22119 3
8192.0 16384.0 12352.0 1600.0 1216.0 1600.0 1216.0 13184.0 9920.0 22119 3

参数说明:

显示列名 具体描述
NGCMN 年轻代(young)中初始化(最小)的大小(KB)
NGCMX 年轻代(young)的最大容量 (KB)
NGC 年轻代(young)中当前的容量 (KB)
S0CMX 年轻代中第一个survivor(幸存区)的最大容量 (KB)
S0C 年轻代中第一个survivor(幸存区)的容量 (KB)
S1CMX 年轻代中第二个survivor(幸存区)的最大容量 (KB)
S1C 年轻代中第二个survivor(幸存区)的容量 (KB)
ECMX 年轻代中Eden(伊甸园)的最大容量 (KB)
EC 年轻代中Eden(伊甸园)的容量 (KB)
YGC 从应用程序启动到采样时年轻代中gc次数
FGC 从应用程序启动到采样时old代(全gc)gc次数

-gcold(统计老年代的情况)

示例:每5秒一次 打印3次 显示进程号为1601的显示old代对象的信息

script
1
2
3
4
5
6
[root@iZ94sbzk035Z ~]# jstat -gcold 1601 5000 3
MC MU CCSC CCSU OC OU YGC FGC FGCT GCT
24960.0 20411.5 5248.0 2736.0 12292.0 8243.2 22120 3 0.147 44.381
24960.0 20411.5 5248.0 2736.0 12292.0 8243.2 22120 3 0.147 44.381
24960.0 20411.5 5248.0 2736.0 12292.0 8243.2 22120 3 0.147 44.381

参数说明:

显示列名 具体描述
MC
MU
CCSC
CCSU
OC Old代的容量 (KB)
OU Old代目前已使用空间 (KB)
YGC 从应用程序启动到采样时年轻代中gc次数
FGC 从应用程序启动到采样时old代(全gc)gc次数
FGCT 从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT 从应用程序启动到采样时gc用的总时间(s)

-gcoldcapacity(统计老年代 heap容量)

示例:每5秒一次 打印3次 显示进程号为1601的显示old代对象的信息及其占用量。

script
1
2
3
4
5
[root@iZ94sbzk035Z ~]# jstat -gcoldcapacity 1601 5000 3
OGCMN OGCMX OGC OC YGC FGC FGCT GCT
8192.0 16384.0 12292.0 12292.0 22122 3 0.147 44.385
8192.0 16384.0 12292.0 12292.0 22122 3 0.147 44.385
8192.0 16384.0 12292.0 12292.0 22122 3 0.147 44.385

参数说明:

显示列名 具体描述
OGCMN old代中初始化(最小)的大小 (KB)
OGCMX old代的最大容量(KB)
OGC old代当前新生成的容量 (KB)
OC Old代的容量 (KB)
YGC 从应用程序启动到采样时年轻代中gc次数
FGC 从应用程序启动到采样时old代(全gc)gc次数
FGCT 从应用程序启动到采样时old代(全gc)gc所用时间(s)
GCT 从应用程序启动到采样时gc用的总时间(s)

如何保证消息不丢失

消息丢失场景

生产者消息丢失

问题

  • 外界环境问题导致:发生网络丢包、网络故障等造成RabbitMQ Server端收不到消息,因为生产环境的网络是很复杂的,网络抖动,丢包现象很常见
    • 一般情况下,生产者使用Confirm模式投递消息,如果方案不够严谨,比如RabbitMQ Server 接收消息失败后会发送nack消息通知生产者,生产者监听消息失败或者没做任何事情,消息存在丢失风险;
  • 代码层面,配置层面,考虑不全导致消息丢失
    • 生产者发送消息到exchange后,发送的路由和queue没有绑定,消息会存在丢失情况,下面会讲到具体的例子,保证意外情况的发生,即使发生,也在可控范围内。

MQ存储的消息丢失或可靠性不足

  • 消息未完全持久化,当机器重启后,消息会全部丢失,甚至Queue也不见了
  • 单节点模式问题,如果某个节点挂了,消息就不能用了,业务可能瘫痪,只能等待
    • 如果做了消息持久化方案,消息会持久化硬盘,机器重启后消息不会丢失;但是还有一个极端情况,这台服务器磁盘突然坏了(公司遇到过磁盘问题还是很多的),消息持久化不了,非高可用状态,这个模式生产环境慎重考虑。
  • 普通集群模式:某个节点挂了,该节点上的消息不能用,有影响的业务瘫痪,只能等待节点恢复重启可用(建立在消息持久化)
    • RabbitMQ 集群模式有点特殊,队列的内容仅仅存在某一个节点上面,不会存在所有节点上面,所有节点仅仅存放消息结构和元数据
  • 镜像模式:可以解决上面的问题,但是还是有意外情况发生
    • 比如:持久化的消息,保存到硬盘过程中,当前队列节点挂了,存储节点硬盘又坏了,消息丢了,怎么办?

消费者消息丢失

消费端接收到相关消息之后,消费端还没来得及处理消息,消费端机器就宕机了,此时消息如果处理不当会有丢失风险

如何避免消息丢失?

下面也是从三个方面介绍:
1.生产者消息如何不丢
2.MQ中存储的消息如何保证
3.消费者消息如何不丢

消息幂等性

幂等性

概念

用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。

举个最简单的例子,那就是支付,用户购买商品后支付,支付扣款成功,但是返回结果的时候网络异常,此时钱已经扣了,
用户再次点击按钮,此时会进行第二次扣款,返回结果成功,用户查询余额发现多扣钱了,流水记录也变成了两条。
在以前的单应用系统中,我们只需要把数据操作放入事务中即可,发生错误立即回滚,但是再响应客户端的时候也有可能出现网络中断或者异常等等

消息重复消费

消费者在消费 MQ 中的消息时,MQ 已把消息发送给消费者,消费者在给 MQ 返回 ack 时网络中断,故 MQ 未收到确认信息,该条消息会重新发给其他的消费者,
或者在网络重连后再次发送给该消费者,但实际上该消费者已成功消费了该条消息,造成消费者消费了重复的消息。

常用消息幂等性解决方案

利用数据库的唯一约束实现幂等

比如将订单表中的订单编号设置为唯一索引,创建订单时,根据订单编号就可以保证幂等

redis的原子性机制

每次操作都直接set到redis里面,然后将redis数据定时同步到数据库中。

乐观锁机制

此方案多用于更新的场景下。
其实现的大体思路是:给业务数据增加一个版本号属性,每次更新数据前,比较当前数据的版本号是否和消息中的版本一致,如果不一致则拒绝更新数据,更新数据的同时将版本号+1。

全局唯一ID

生产者发送每条数据的时候,增加一个全局唯一的id,这个id通常是业务的唯一标识,比如订单编号。
在消费端消费时,则验证该id是否被消费过,如果还没消费过,则进行业务处理。处理结束后,在把该id存入redis,同时设置状态为已消费。如果已经消费过了,则不进行处理。

推荐使用

使用全局唯一ID 或 乐观锁机制。
当在集群环境下,出现消息幂等性问题后,可以使用 [分布式锁+全局唯一id] 或 [分布式锁+乐观锁机制]

RabbitMQ消息丢失场景

生产者消息丢失

  • 外界环境问题导致:发生网络丢包、网络故障等造成RabbitMQ Server端收不到消息,因为生产环境的网络是很复杂的,网络抖动,丢包现象很常见
    • 一般情况下,生产者使用Confirm模式投递消息,如果方案不够严谨,比如RabbitMQ Server 接收消息失败后会发送nack消息通知生产者,生产者监听消息失败或者没做任何事情,消息存在丢失风险;
  • 代码层面,配置层面,考虑不全导致消息丢失
    • 生产者发送消息到exchange后,发送的路由和queue没有绑定,消息会存在丢失情况,下面会讲到具体的例子,保证意外情况的发生,即使发生,也在可控范围内。
阅读全文 »

为什么要用搜索引擎

  • 数据类型
    全文索引搜索支持非结构化数据的搜索,可以更好地快速搜索大量存在的任何单词或单词组的非结构化文本。
    例如 Google,百度类的网站搜索,它们都是根据网页中的关键字生成索引,我们在搜索的时候输入关键字,它们会将该关键字即索引匹配到的所有网页返回;还有常见的项目中应用日志的搜索等等。对于这些非结构化的数据文本,关系型数据库搜索不是能很好的支持。

  • 索引的维护
    一般传统数据库,全文检索都实现的很鸡肋,因为一般也没人用数据库存文本字段。进行全文检索需要扫描整个表,如果数据量大的话即使对SQL的语法优化,也收效甚微。建立了索引,但是维护起来也很麻烦,对于 insert 和 update 操作都会重新构建索引。

什么时候使用全文搜索引擎

  • 搜索的数据对象是大量的非结构化的文本数据。
  • 文件记录量达到数十万或数百万个甚至更多。
  • 支持大量基于交互式文本的查询。
  • 需求非常灵活的全文搜索查询。
  • 对高度相关的搜索结果的有特殊需求,但是没有可用的关系数据库可以满足。
  • 对不同记录类型、非文本数据操作或安全事务处理的需求相对较少的情况。

倒排索引

倒排索引是实现“单词-文档矩阵”的一种具体存储形式,通过倒排索引,可以根据单词快速获取包含这个单词的文档列表。倒排索引主要由两个部分组成:“单词词典”和“倒排文件”。例如
document1 : welcome to china
document2 : china is beautiful
document3 : tom like china

单词字典 倒排文件
welcome 1
to 1
china 1,2,3
is 2
beautiful 2
tom 3
like 3

在建立倒排索引时,会使用标准化规则(normalization),会将document分词出来的单词字典 进行标准化处理,比如:
* 缩写 vs. 全程:cn vs. china
* 格式转化:like liked likes
* 大小写:Tom vs tom
* 同义词:like vs love

什么是分词器

切分词语,normalization(提升recall召回率),将一段文本进行各种处理,最后处理好的结果才会拿去建立倒排索引
recall-召回率:搜索时增加能够搜索到的结果数量

分词其包含三部分:

  • character filter-过滤特殊字符:分词前先进行预处理,最常见的就是过滤html标签等
  • tokenizer-分词: hello you and me –> hello, you, and, me
  • token filter-进行标准化处理:标准化处理,比如缩写、格式转化、大小写、同义词等

内置分词器的介绍

document 案例:Set the shape to semi-transparent by calling set_trans(5)

  • standard analyzer: 大小写转化,去除一些特殊符号、大小写拆分(es默认的分词器)
    set, the, shape, to, semi, transparent, by, calling, set_trans, 5
  • simple analyzer:去除一些特殊符号,可以依据-,_来拆分字符
    set, the, shape, to, semi, transparent, by, calling, set, trans
  • whitespace analyzer: 自会根据空格进行拆分,不会处理大小写 特殊字符
    Set, the, shape, to, semi-transparent, by, calling, set_trans(5)
  • language analyzer: 特定的语言的分词器,比如说,english,英语分词器
    set, shape, semi, transpar, call, set_tran, 5

测试分词器

script
1
2
3
4
5
GET /_analyze
{
"analyzer": "standard", # 给定的分词器
"text": "Text to analyze" # 待分词的文本
}

返回结果

script
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
{
"tokens" : [
{
"token" : "text",
"start_offset" : 0,
"end_offset" : 4,
"type" : "<ALPHANUM>",
"position" : 0
},
{
"token" : "to",
"start_offset" : 5,
"end_offset" : 7,
"type" : "<ALPHANUM>",
"position" : 1
},
{
"token" : "analyze",
"start_offset" : 8,
"end_offset" : 15,
"type" : "<ALPHANUM>",
"position" : 2
}
]
}

相关度分数 TF & IDF算法

算法介绍

relevance score算法,简单来说,就是计算出,一个索引中的文本,与搜索文本,他们之间的关联匹配程度
Elasticsearch使用的是 term frequency/inverse document frequency算法,简称为TF/IDF算法

  • term frequency(TF算法)
    搜索文本中的各个词条在field文本中出现了多少次,出现次数越多,就越相关
    1
    2
    3
    4
    5
    搜索请求:hello world  
    doc1:hello you, and world is very good
    doc2:hello, how are you

    根据TF算法 doc1 相关度分数最高,应该分词后,匹配了 hello和world
  • inverse document frequency(IDF算法)
    搜索文本中的各个词条在整个索引的所有文档中出现了多少次,出现的次数越多,就越不相关
    1
    2
    3
    4
    5
    6
    7
    搜索请求:hello world
    doc1:hello, today is very good
    doc2:hi world, how are you

    场景:如果index中有1万条document,hello这个单词在所有的document中出现了1000次,world这个单词在所有的document中出现了100次

    根据IDF算法 doc2 相关度分数最高,因为只有doc2中才有world

Field-length norm field长度

field 长度越长,相关度越弱

1
2
3
4
5
6
7
搜索请求:hello world

doc1:{ "title": "hello article", "content": "babaaba 1万个单词" }
doc2:{ "title": "my article", "content": "blablabala 1万个单词,hi world" }

通过分词再搜索,hello world 在doc1 和doc2中出现的次数一样
doc1 相关度分数最高 title field长度更短

es 分布式框架简述

es 对分布式机制的透明隐藏特性

Elasticsearch是一套分布式的系统,分布式是为了应对大数据量隐藏了复杂的分布式机制

  • 分片机制
    将数据写入document时,数据如何进行分片,写入那个shard中等等
  • cluster discovery(集群发现机制):
    如扩展集群时,启动第二个es进程,那个进程作为一个node自动就发现了集群,并且加入了进去,还接受了部分数据,replica shard
  • shard的负载均衡
    举例,假设现在有3个节点,总共有25个shard要分配到3个节点上去,es会自动进行均匀分配,以保持每个节点的均衡的读写负载请求
    其实是通过coordinate node 来处理的

es 集群的扩容方式

如现有集群 3集群 每台服务器能容纳1T数据 3个node 3个primary shard replica shard 设置为2  
  • 水平扩容
    集群数量+1 当前服务器*4 增加一个node节点 now 4个node 通过master node 将 replica shard copy过去 (现有primary shard 已经最大)
    优点:提升集群的容错性能,多一个node 可以更好的应对单节点故障所产生的风险,提供并发处理能力
    es 集群 结构图
  • 垂直扩容
    集群数量不变,增加某台服务内存或者集群内所有的机器加内存,比如 由现有的1T 变为2T
    优点:使得单台node的处理性能变的更佳
    缺点:垂直扩容,成本相对应的成倍增加,应对节点故障,对比扩容前无改变
    一般采用水平扩容。

水平扩容的极限 以及如何提高容错性

* primary&replica自动负载均衡,6个shard 3个primary shard 3个replica shard
* 每个node 有更少的shard,这是 IO/CUP/Mamory 资源给每个shard也就越多,每个shard的性能也就越好
* 扩容极限 6个shard(3个primary 3个replica) 最多扩容到6台机器,一个shard独享node的 所有资源 性能最好
* 超出扩容极限 动态修改replica数量,9个shard(3个primary 6个replica),9台机器比3台机器时 拥有了3倍的吞吐量
* 容错 3台机器 6个shard(3个primary 3个replica)容忍1台机器宕机,3台机器 9个shard(3个primary 6个replica)容忍2台机器宕机,同一个primary与replica不能同时在一个node上出现

es 集群的master节点

* master 节点不会承载所有的请求,所有不会有单点瓶颈
* 管理es集群的元数据:
    比如document的创建、修改和删除,维护索引的元数据;节点的新增和删除,维护集群的元数据(水平扩容)
* 默认情况下,集群会自动选举出一个master节点,如master节点出现故障后,集群会在剩余节点中选出一个master节点

节点平等的分布式架构

* 节点对等,每个节点都可以接收到所有请求
* 自动请求路由 client的请求发送到某个节点时,这个节点会自动去请求对应的index  
* 相应收集 收到请求的节点,将请求转发出去后,相应结果会返回改节点 有改节点统一发给client 这个节点 就是 coordidata node

写一致性以及quorum机制

写一致性

在发送任何es的 增删改操作时,都可以带一个consistency参数,来指明想要的写一致性是什么  
consistency: one、all、quorum
* one: 要求写操作时,只要<font color=red>有一个primary shard</font> 是active,就可以执行
* all:要求写操作时,必须<font color=red>所有的primary shard 和replica shard</font> 都是active,才可以执行这个写操作
* quorum: 要求所有的shard中,必须是<font color=red>大部分shard</font> 都是active,才可以执行这个写操作

quorum机制

写之前 需确保大多数的shard是可用的,且只有在 <font color=red>number_of_replica > 1是才生效</font>  
quroum = int((primary + number_of_replica)/2 ) + 1  

* 场景1 3台服务器 3个primary replicas 为1 6个shard: 3primary replica:1*3 
    quroum = int ((3+ 1)/2) + 1 = 3  
    也就是说明 3台服务器 6个shard 时 有两个node 也就是4个shard是active时 可以进行写操作
* 场景2 3台服务器 3个primary 3个replica  
     quroum = int ((3+ 3)/2) + 1 = 4 当shard 中active数>4时可进行写操作  
     注:如果此时宕机2台机器 那么shard的active数 只有3 这时不能进行写操作 但是可以进行读操作
     
* 场景3 单机场景下 一个primary shard replica 默认为1 0个active  
    因为 number_of_replica = 1 不触发quroum 一致性 也就是说可以支持读写操作

* time_out 当quorum 不齐全时,es会等待wait  
    默认1分钟 time_out可以设置时长 可长可短 time_out=30s time_out=30ms time_out=1m  
    超时则写入失败
    格式 PUT test_index/type/1?time_out=30ms

如何进行版本控制

  • 乐观锁并发控制方案
    基于版本号来判断,当前操作的document是否为最新,每次操作前对比当前版本号与es集群之前的差别

  • 悲观锁并发控制方案
    在各种情况下都上锁,上锁之后,就只有一个线程可以操作这一条数据了,不同场景下锁不同,如:行锁,表锁,读锁,写锁等。

es基于乐观锁实现的版本控制

  • 基于系统自带的版本号

    • 老版本 进行写操作时,在操作语句后面添加_version=n(n:表示es集群中document的版本号),与集群中的version比较,小于版本号时不执行更新操作
    • 新版本 在写操作时,取消_version字段,改为 if_seq_no=n&if_primary_term来比较版本,取值分别取查询结果中的_seq_no和_primary_term
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      {
      "_index" : "test_index",
      "_type" : "type",
      "_id" : "1",
      "_version" : 4,
      "_seq_no" : 4,
      "_primary_term" : 1,
      "found" : true,
      "_source" : {
      "test_fild" : "test1-3"
      }
      }
  • 业务所用的版本号
    在写操作时,添加version=5&version_type=external 这里的5位外部业务系统控制的版本号为5

partial update乐观锁并发控制

partial update 内部会自动执行 乐观锁的并发控制策略 如果发现版本号不一致时,partial update 会自动 fail掉

重试策略: retry策略

  • 再次获取document数据和最新的版本号
  • 基于最新的版本号再次去更新,如果成功就return
  • 如果失败了,重复执行1和2步骤,具体重试次数,可通过设置retry的参数指定执行次数

大龄剩女着急结婚的,基本上都有难言之隐。
大龄剩女经历得多,心思重,城府深,你要是不提防着她,弄不巧就阴沟里翻船——底朝天啊。
兄弟,送你一句话:看一个女人要看她的过去,看一个男人要看他的未来。
现在的舆论环境,把女性捧得比天还高,如果我要是把这些话说出来了,我还不得被喷死。
男人嘛,表面上要学会给女性说好话听,谁也不得罪。毕竟如果你要是得罪了一个女人,你基本上得罪了一个范围内的所有女人。
所以在舆论上来说,尽量顺了女性的心意,把她们往天上吹,这样你就会成为一个受欢迎的男人。因为女人堆里提到你就是好男人,这样更多的女性会把你当成一个潜在的交往对象,你的资源不就多了起来了吗?
我说的那些对女性的要求,都是不能说出来的,因为说出来,会被喷成大男子主义,这样就很难在女人圈子里搞好名声了。
所以,和女人交往,一定要在嘴上尽情地吹捧她们。
但是,在要不要结婚的关键时刻,千万不要放下自己的要求,这时候最好的办法就是找一些既不影响自己的口碑,又能够拒绝对方的理由来加以回绝。
在拒绝的时候,一定要同时吹捧对方,让她还是飘在天上,不能掉地上,毕竟你要是打破了对方的梦,她还不得在背后嚼舌根把你踩到泥土里,够你受的。
对女人,千万不要跟她讲道理。因为女性是活在幻想中的,她们根本不愿意接受道理,更不要说面对现实了,讲了也没用,而且还会遭人烦。
最好的办法就是,无脑吹,把她们捧到天上去。慢慢地,时间会让她们从天上掉下来的。
记住:打败女人的,唯有时间!熬过那几年,她比你要着急。
不要听什么说现在能够养活自己,做一个独立的女人这种鬼话。
那是她们还年轻,那是她们还有父母做后盾。一场疫情下来,经济下滑了,看看有多少女人想结婚。
经济好的时候,女人能赚点钱养活自己,可以对外宣称自己不需要男人;经济变差了,养活不了自己了,开始想着结婚了。
经济会一直好下去吗?会一直年轻能赚钱吗?
能赚钱的只有少数人,那些
男人,把所有的时间放在搞钱上,你要是像我这么有钱,你就会发现,你再也看不上那些年龄超过30岁的女人了,因为你想要的她们早已没了,她们有的,你也早都有了。
不要着急,因为,她们比你还着急,哈哈!