diff --git a/Architecture.md b/Architecture.md index e1e4947..381f1d2 100644 --- a/Architecture.md +++ b/Architecture.md @@ -4952,4 +4952,118 @@ id 为6001 的新闻点击数加1:zincrby hotNews:20190926 1 n6001 获取今天点击最多的15条:zrevrange hotNews:20190926 0 15 withscores -![1586782291610](images/Architecture/20200413205344663.png) \ No newline at end of file +![1586782291610](images/Architecture/20200413205344663.png) + + + +# 分布式问题场景 + +## 消息队列 —— 幂等问题 + +**微信支付结果通知场景** + +- 微信官方文档上提到微信支付通知结果可能会推送多次,需要开发者自行保证幂等性。第一次我们可以直接修改订单状态(如支付中 -> 支付成功),第二次就根据订单状态来判断,如果不是支付中,则不进行订单处理逻辑。 + + + +**插入数据库场景** + +- 每次插入数据时,先检查下数据库中是否有这条数据的主键 id,如果有,则进行更新操作。 + + + +**写 Redis 场景** + +- Redis 的 `Set` 操作天然幂等性,所以不用考虑 Redis 写数据的问题。 + + + +**其他场景方案** + +- 生产者发送每条数据时,增加一个全局唯一 id,类似订单 id。每次消费时,先去 Redis 查下是否有这个 id,如果没有,则进行正常处理消息,且将 id 存到 Redis。如果查到有这个 id,说明之前消费过,则不要进行重复处理这条消息 +- 不同业务场景,可能会有不同的幂等性方案,大家选择合适的即可,上面的几种方案只是提供常见的解决思路。 + + + +## 消息队列 —— 消息丢失 + +### 生产者存放消息的过程中丢失消息 + +![生产者存放消息的过程中丢失消息](images/Architecture/生产者存放消息的过程中丢失消息.jpg) + +**解决方案** + +- 事务机制(不推荐,异步方式) + +对于 RabbitMQ 来说,生产者发送数据之前开启 RabbitMQ 的**事务机制**`channel.txselect` ,如果消息没有进队列,则生产者受到异常报错,并进行回滚 `channel.txRollback`,然后重试发送消息;如果收到了消息,则可以提交事务 `channel.txCommit`。但这是一个同步的操作,会影响性能。 + +- confirm 机制(推荐,异步方式) + +我们可以采用另外一种模式:`confirm` 模式来解决同步机制的性能问题。每次生产者发送的消息都会分配一个唯一的 id,如果写入到了 RabbitMQ 队列中,则 RabbitMQ 会回传一个 `ack` 消息,说明这个消息接收成功。如果 RabbitMQ 没能处理这个消息,则回调 `nack` 接口。说明需要重试发送消息。 + +也可以自定义超时时间 + 消息 id 来实现超时等待后重试机制。但可能出现的问题是调用 ack 接口时失败了,所以会出现消息被发送两次的问题,这个时候就需要保证消费者消费消息的幂等性。 + + + +`事务模式` 和 `confirm` 模式的区别: + +- 事务机制是同步的,提交事务后悔被**阻塞**直到提交事务完成后。 +- confirm 模式异步接收通知,但可能**接收不到通知**。需要考虑接收不到通知的场景。 + + + +### 消息队列丢失消息 + +![消息队列丢失消息](images/Architecture/消息队列丢失消息.png) + +消息队列的消息可以放到内存中,或将内存中的消息转到硬盘(比如数据库)中,一般都是内存和硬盘中都存有消息。如果只是放在内存中,那么当机器重启了,消息就全部丢失了。如果是硬盘中,则可能存在一种极端情况,就是将内存中的数据转换到硬盘的期间中,消息队列出问题了,未能将消息持久化到硬盘。 + +**解决方案** + +- 创建 `Queue` 的时候将其设置为持久化。 +- 发送消息的时候将消息的 `deliveryMode` 设置为 2 。 +- 开启生产者 `confirm` 模式,可以重试发送消息。 + + + +### 消费者丢失消息 + +![消费者丢失消息](images/Architecture/消费者丢失消息.png) + +消费者刚拿到数据,还没开始处理消息,结果进程因为异常退出了,消费者没有机会再次拿到消息。 + +**解决方案** + +- 关闭 RabbitMQ 的自动 `ack`,每次生产者将消息写入消息队列后,就自动回传一个 `ack` 给生产者。 +- 消费者处理完消息再主动 `ack`,告诉消息队列我处理完了。 + +**问题:** 那这种主动 `ack` 有什么漏洞了?如果 主动 `ack` 的时候挂了,怎么办? + +则可能会被再次消费,这个时候就需要幂等处理了。 + +**问题:** 如果这条消息一直被重复消费怎么办? + +则需要有加上重试次数的监测,如果超过一定次数则将消息丢失,记录到异常表或发送异常通知给值班人员。 + + + +## 消息队列 —— 消息乱序 + +## 消息队列 —— 消息积压 + +## 消息队列 —— 消息过期失效 + +## 消息队列 —— 队列写满 + +## Redis —— 数据丢失 + +## 分库分表 —— 扩容 + +## 分库分表 —— 唯一ID + +## 分布式事务 + + + + + diff --git a/DevOps.md b/DevOps.md index 946b378..f65a9ef 100644 --- a/DevOps.md +++ b/DevOps.md @@ -330,6 +330,91 @@ df -h +## Install + +### rpm + +```shell +rpm -ivh package.rpm # 安装一个rpm包 +rpm -ivh --nodeeps package.rpm # 安装一个rpm包而忽略依赖关系警告 +rpm -U package.rpm # 更新一个rpm包但不改变其配置文件 +rpm -F package.rpm # 更新一个确定已经安装的rpm包 +rpm -e package_name.rpm # 删除一个rpm包 +rpm -qa # 显示系统中所有已经安装的rpm包 +rpm -qa | grep httpd # 显示所有名称中包含 "httpd" 字样的rpm包 +rpm -qi package_name # 获取一个已安装包的特殊信息 +rpm -qg "System Environment/Daemons" # 显示一个组件的rpm包 +rpm -ql package_name # 显示一个已经安装的rpm包提供的文件列表 +rpm -qc package_name # 显示一个已经安装的rpm包提供的配置文件列表 +rpm -q package_name --whatrequires # 显示与一个rpm包存在依赖关系的列表 +rpm -q package_name --whatprovides # 显示一个rpm包所占的体积 +rpm -q package_name --scripts # 显示在安装/删除期间所执行的脚本l +rpm -q package_name --changelog # 显示一个rpm包的修改历史 +rpm -qf /etc/httpd/conf/httpd.conf # 确认所给的文件由哪个rpm包所提供 +rpm -qp package.rpm -l # 显示由一个尚未安装的rpm包提供的文件列表 +rpm --import /media/cdrom/RPM-GPG-KEY # 导入公钥数字证书 +rpm --checksig package.rpm # 确认一个rpm包的完整性 +rpm -qa gpg-pubkey # 确认已安装的所有rpm包的完整性 +rpm -V package_name # 检查文件尺寸、 许可、类型、所有者、群组、MD5检查以及最后修改时间 +rpm -Va # 检查系统中所有已安装的rpm包- 小心使用 +rpm -Vp package.rpm # 确认一个rpm包还未安装 +rpm2cpio package.rpm | cpio --extract --make-directories *bin* # 从一个rpm包运行可执行文件 +rpm -ivh /usr/src/redhat/RPMS/`arch`/package.rpm # 从一个rpm源码安装一个构建好的包 +rpmbuild --rebuild package_name.src.rpm # 从一个rpm源码构建一个 rpm 包 +``` + + + +### yum + +```shell +# 下载并安装一个rpm包 +yum install package_name +# 将安装一个rpm包,使用你自己的软件仓库为你解决所有依赖关系 +yum localinstall package_name.rpm +# 更新当前系统中所有安装的rpm包 +yum update package_name.rpm +# 更新一个rpm包 +yum update package_name +# 删除一个rpm包 +yum remove package_name +# 列出当前系统中安装的所有包 +yum list +# 在rpm仓库中搜寻软件包 +yum search package_name +# 删除所有缓存的包和头文件 +yum clean all +``` + + + +### deb/apt + +```shell +dpkg -i package.deb # 安装/更新一个 deb 包 +dpkg -r package_name # 从系统删除一个 deb 包 +dpkg -l # 显示系统中所有已经安装的 deb 包 +dpkg -l | grep httpd # 显示所有名称中包含 "httpd" 字样的deb包 +dpkg -s package_name # 获得已经安装在系统中一个特殊包的信息 +dpkg -L package_name # 显示系统中已经安装的一个deb包所提供的文件列表 +dpkg --contents package.deb # 显示尚未安装的一个包所提供的文件列表 +dpkg -S /bin/ping # 确认所给的文件由哪个deb包提供 + +# APT 软件工具 (Debian, Ubuntu 以及类似系统) +apt-get install package_name # 安装/更新一个 deb 包 +apt-cdrom install package_name # 从光盘安装/更新一个 deb 包 +apt-get update # 升级列表中的软件包 +apt-get upgrade # 升级所有已安装的软件 +apt-get remove package_name # 从系统删除一个deb包 +apt-get check # 确认依赖的软件仓库正确 +apt-get clean # 从下载的软件包中清理缓存 +apt-cache search searched-package # 返回包含所要搜索字符串的软件包名称 +``` + + + +## Filter + ### tail ```shell @@ -597,87 +682,6 @@ telnet 10.150.159.71 5516 -### rpm - -```shell -rpm -ivh package.rpm # 安装一个rpm包 -rpm -ivh --nodeeps package.rpm # 安装一个rpm包而忽略依赖关系警告 -rpm -U package.rpm # 更新一个rpm包但不改变其配置文件 -rpm -F package.rpm # 更新一个确定已经安装的rpm包 -rpm -e package_name.rpm # 删除一个rpm包 -rpm -qa # 显示系统中所有已经安装的rpm包 -rpm -qa | grep httpd # 显示所有名称中包含 "httpd" 字样的rpm包 -rpm -qi package_name # 获取一个已安装包的特殊信息 -rpm -qg "System Environment/Daemons" # 显示一个组件的rpm包 -rpm -ql package_name # 显示一个已经安装的rpm包提供的文件列表 -rpm -qc package_name # 显示一个已经安装的rpm包提供的配置文件列表 -rpm -q package_name --whatrequires # 显示与一个rpm包存在依赖关系的列表 -rpm -q package_name --whatprovides # 显示一个rpm包所占的体积 -rpm -q package_name --scripts # 显示在安装/删除期间所执行的脚本l -rpm -q package_name --changelog # 显示一个rpm包的修改历史 -rpm -qf /etc/httpd/conf/httpd.conf # 确认所给的文件由哪个rpm包所提供 -rpm -qp package.rpm -l # 显示由一个尚未安装的rpm包提供的文件列表 -rpm --import /media/cdrom/RPM-GPG-KEY # 导入公钥数字证书 -rpm --checksig package.rpm # 确认一个rpm包的完整性 -rpm -qa gpg-pubkey # 确认已安装的所有rpm包的完整性 -rpm -V package_name # 检查文件尺寸、 许可、类型、所有者、群组、MD5检查以及最后修改时间 -rpm -Va # 检查系统中所有已安装的rpm包- 小心使用 -rpm -Vp package.rpm # 确认一个rpm包还未安装 -rpm2cpio package.rpm | cpio --extract --make-directories *bin* # 从一个rpm包运行可执行文件 -rpm -ivh /usr/src/redhat/RPMS/`arch`/package.rpm # 从一个rpm源码安装一个构建好的包 -rpmbuild --rebuild package_name.src.rpm # 从一个rpm源码构建一个 rpm 包 -``` - - - -### yum - -```shell -# 下载并安装一个rpm包 -yum install package_name -# 将安装一个rpm包,使用你自己的软件仓库为你解决所有依赖关系 -yum localinstall package_name.rpm -# 更新当前系统中所有安装的rpm包 -yum update package_name.rpm -# 更新一个rpm包 -yum update package_name -# 删除一个rpm包 -yum remove package_name -# 列出当前系统中安装的所有包 -yum list -# 在rpm仓库中搜寻软件包 -yum search package_name -# 删除所有缓存的包和头文件 -yum clean all -``` - - - -### deb/apt - -```shell -dpkg -i package.deb # 安装/更新一个 deb 包 -dpkg -r package_name # 从系统删除一个 deb 包 -dpkg -l # 显示系统中所有已经安装的 deb 包 -dpkg -l | grep httpd # 显示所有名称中包含 "httpd" 字样的deb包 -dpkg -s package_name # 获得已经安装在系统中一个特殊包的信息 -dpkg -L package_name # 显示系统中已经安装的一个deb包所提供的文件列表 -dpkg --contents package.deb # 显示尚未安装的一个包所提供的文件列表 -dpkg -S /bin/ping # 确认所给的文件由哪个deb包提供 - -# APT 软件工具 (Debian, Ubuntu 以及类似系统) -apt-get install package_name # 安装/更新一个 deb 包 -apt-cdrom install package_name # 从光盘安装/更新一个 deb 包 -apt-get update # 升级列表中的软件包 -apt-get upgrade # 升级所有已安装的软件 -apt-get remove package_name # 从系统删除一个deb包 -apt-get check # 确认依赖的软件仓库正确 -apt-get clean # 从下载的软件包中清理缓存 -apt-cache search searched-package # 返回包含所要搜索字符串的软件包名称 -``` - - - ### whereis Linux whereis命令用于查找文件。 @@ -734,115 +738,51 @@ unzip file1.zip # 解压一个zip格式压缩包 -## Monitor - -### Memory - -#### free - -`free`是查看内存使用情况,包括物理内存、交换内存(swap)和内核缓冲区内存。 - -```shell -# 语法 -free [-bkmhotV][-s <间隔秒数>] - -# 参数说明: -# -b  以Byte为单位显示内存使用情况 -# -k  以KB为单位显示内存使用情况 -# -m 以MB为单位显示内存使用情况 -# -h  以合适的单位显示内存使用情况,最大为三位数,自动计算对应单位值。单位:B=bytes, K=kilos, M=megas, G=gigas, T=teras -# -o  不显示缓冲区调节列 -# -s <间隔秒数>  持续观察内存使用状况 -# -t  显示内存总和列 -# -V  显示版本信息 -``` - -`free -h -s 3`表示每隔三秒输出一次内存情况,命令如下: +## Statistics ```shell -[1014154@cc69dd4c5-4tdb5 ~]$ free -h -s 3 - total used free shared buff/cache available -Mem: 114G 41G 43G 4.1G 29G 67G -Swap: 0B 0B 0B - total used free shared buff/cache available -Mem: 114G 41G 43G 4.1G 29G 67G -Swap: 0B 0B 0B -``` - -- `Mem`:是内存的使用情况 -- `Swap`:是交换空间的使用情况 -- `total`:系统总的可用物理内存和交换空间大小 -- `used`:已经被使用的物理内存和交换空间 -- `free`:还有多少物理内存和交换空间可用使用,**是真正尚未被使用的物理内存数量** -- `shared`:被共享使用的物理内存大小 -- `buff/cache`:被 buffer(缓冲区) 和 cache(缓存) 使用的物理内存大小 -- `available`:还可以被应用程序使用的物理内存大小,**它是从应用程序的角度看到的可用内存数量,available ≈ free + buffer + cache** +# 查看某个进程的PID +ps -ef | grep arthas-demo.jar -**交换空间(swap space)** +# 查看java关键词的进程的数量 +ps -ef | grep java| wc -l -swap space 是磁盘上的一块区域,当系统物理内存吃紧时,Linux 会将内存中不常访问的数据保存到 swap 上,这样系统就有更多的物理内存为各个进程服务,而当系统需要访问 swap 上存储的内容时,再将 swap 上的数据加载到内存中,这就是常说的换出和换入。交换空间可以在一定程度上缓解内存不足情况,但它需要读写磁盘数据,所以性能不是很高。 +# 查看线程是否存在死锁 +jstack -l +# 统计某个进程的线程数量 +ps -efL | grep [pid] | wc -l +# 查看某个进制有哪些线程 +ps -Lp [pid] cu -#### vmstat +# 统计所有的log文件中,包含Error字符的行 +find / -type f -name "*.log" | xargs grep "ERROR" -vmstat(Virtual Meomory Statistics,虚拟内存统计)是Linux中监控内存的常用工具,它收集和显示关于**内存**,**进程**,**终端**和**分页**和**I/O阻塞**的概括信息。 +# 统计日志文件中包含特定异常数量 +cat xxx.log | grep ** *Exception| wc -l -```shell -# 每隔1秒打印一次,一共打印3次。-S指定显示单位, M代表Mb, 默认为Kb -[root@localhost ~]# vmstat -SM 1 3 -procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- - r b swpd free buff cache si so bi bo in cs us sy id wa st - 1 0 0 2433 2 657 0 0 132 8 77 95 1 2 97 1 0 - 0 0 0 2433 2 657 0 0 0 0 47 71 0 0 100 0 0 - 0 0 0 2433 2 657 0 0 0 0 54 72 0 0 100 0 0 +# 统计log中301、302状态码的行数,$8表示第八列是状态码,可以根据实际情况更改 +awk'{print $8}' 2017-05-22-access_log|egrep '301|302'| wc -l ``` -- **procs** - - - `r`:表示运行和等待CPU时间片的进程数(就是说多少个进程真的分配到CPU),**这个值如果长期大于系统CPU个数,说明CPU不足,需要增加CPU** - - `b`:表示在等待资源的进程数,比如正在等待I/O或者内存交换等 - -- **memory** - - - `swpd`:表示切换到内存交换区的内存大小,即虚拟内存已使用的大小(单位KB),**如果大于0,表示你的机器物理内存不足了,如果不是程序内存泄露的原因,那么你该升级内存了或者把耗内存的任务迁移到其他机器** - - `free`:表示当前空闲的物理内存 - - `buff`:表示缓冲大小,一般对块设备的读写才需要缓冲 - - `cache`:表示缓存大小,一般作为文件系统进行缓冲,频繁访问的文件都会被缓存,如果cache值非常大说明缓存文件比较多,如果此时io中的bi比较小,说明文件系统效率比较好 - -- **swap**:交换空间 - - 一般情况下si、so的值都为0,如果si、so的值长期不为0,则说明系统内存不足,需要增加系统内存。 - - - `si`:表示数据由磁盘读入内存;通俗的讲就是每秒从磁盘读入虚拟内存的大小,**如果这个值大于0,表示物理内存不够用或者内存泄露了,要查找耗内存进程解决掉** - - `so`:表示由内存写入磁盘,也就是由内存交换区进入内存的数据大小 - -- **io** - - 如果bi+bo的值过大,且wa值较大,则表示系统磁盘IO瓶颈。 - - - `bi`:表示由块设备读入数据的总量,即读磁盘,单位kb/s - - `bo`:表示写到块设备数据的总量,即写磁盘,单位kb/s -- **system** - 这两个值越大,则由内核消耗的CPU就越多。 +# Linux Monitor - - `in`:表示某一时间间隔内观测到的每秒设备终端数 - - `cs`:表示每秒产生的上下文切换次数,**这个值要越小越好,太大了,要考虑调低线程或者进程的数目** +![img](images/DevOps/1657486-20200110163906854-1971599861.png) -- **CPU(百分比)** +## CPU - - `us`:表示用户进程消耗的CPU时间比,**us值越高,说明用户进程消耗CPU时间越多。如果长期大于50%,则需要考虑优化程序或者算法** - - `sy`:表示系统内核进程消耗的CPU时间比,**一般us+sy应该小于80%,如果大于80%,说明可能存在CPU瓶颈** - - `id`:表示CPU处在空间状态的时间百分比 - - `wa`:表示IP等待所占用的CPU时间百分比,**wa值越高,说明I/O等待越严重,根据经验wa的参考值为20%,如果超过20%,说明I/O等待严重,引起I/O等待的原因可能是磁盘大量随机读写造成的,也可能是磁盘或者监控器的贷款瓶颈(主要是块操作)造成的** +从 CPU 的角度来说,主要的性能指标就是 **CPU 的使用率**、**上下文切换**以及 **CPU 缓存的命中率**等。 +![img](images/DevOps/d474b437af17bd1d35eb6f64b520a8ac.png) +![img](images/DevOps/1477786-20201122134301506-441066821.png) -### CPU +![img](images/DevOps/9ca30729b6120a06dff8d3c72a93f8e2.png) -#### top +### top top可以查看CPU总体消耗,包括分项消耗,如User,System,Idle,nice等。 @@ -878,7 +818,7 @@ KiB Swap: 0 total, 0 free, 0 used. 75402760 avail Mem -#### htop +### htop htop基本上是一个top改善版本,它能够以更加多彩的方式显示更多的统计信息,同时允许你采用不同的方式进行排序,它提供了一个用户友好的接口。 @@ -888,7 +828,7 @@ htop基本上是一个top改善版本,它能够以更加多彩的方式显示 -#### sar +### sar ① 通过`sar -u 1 3`可以查看CUP总体消耗占比,每间隔1秒钟统计1次总共统计3次: @@ -930,9 +870,127 @@ Linux 3.10.0-1062.el7.x86_64 (localhost.localdomain) 2020年05月01日 _x86_ -### IO +## Memory + +从内存的角度来说,主要的性能指标,就是系统内存的分配和使用、进程内存的分配和使用以及 SWAP 的用量。 + +![img](images/DevOps/4dc3e5aba96c56ac1b3e8d51611934dd.png) + +![img](images/DevOps/1477786-20201122135426680-1563483565.png) + +![img](images/DevOps/b4e930f089487cc2431f3f2f067f0425.png) -#### iostat +### free + +`free`是查看内存使用情况,包括物理内存、交换内存(swap)和内核缓冲区内存。 + +```shell +# 语法 +free [-bkmhotV][-s <间隔秒数>] + +# 参数说明: +# -b  以Byte为单位显示内存使用情况 +# -k  以KB为单位显示内存使用情况 +# -m 以MB为单位显示内存使用情况 +# -h  以合适的单位显示内存使用情况,最大为三位数,自动计算对应单位值。单位:B=bytes, K=kilos, M=megas, G=gigas, T=teras +# -o  不显示缓冲区调节列 +# -s <间隔秒数>  持续观察内存使用状况 +# -t  显示内存总和列 +# -V  显示版本信息 +``` + +`free -h -s 3`表示每隔三秒输出一次内存情况,命令如下: + +```shell +[1014154@cc69dd4c5-4tdb5 ~]$ free -h -s 3 + total used free shared buff/cache available +Mem: 114G 41G 43G 4.1G 29G 67G +Swap: 0B 0B 0B + total used free shared buff/cache available +Mem: 114G 41G 43G 4.1G 29G 67G +Swap: 0B 0B 0B +``` + +- `Mem`:是内存的使用情况 +- `Swap`:是交换空间的使用情况 +- `total`:系统总的可用物理内存和交换空间大小 +- `used`:已经被使用的物理内存和交换空间 +- `free`:还有多少物理内存和交换空间可用使用,**是真正尚未被使用的物理内存数量** +- `shared`:被共享使用的物理内存大小 +- `buff/cache`:被 buffer(缓冲区) 和 cache(缓存) 使用的物理内存大小 +- `available`:还可以被应用程序使用的物理内存大小,**它是从应用程序的角度看到的可用内存数量,available ≈ free + buffer + cache** + +**交换空间(swap space)** + +swap space 是磁盘上的一块区域,当系统物理内存吃紧时,Linux 会将内存中不常访问的数据保存到 swap 上,这样系统就有更多的物理内存为各个进程服务,而当系统需要访问 swap 上存储的内容时,再将 swap 上的数据加载到内存中,这就是常说的换出和换入。交换空间可以在一定程度上缓解内存不足情况,但它需要读写磁盘数据,所以性能不是很高。 + + + +### vmstat + +vmstat(Virtual Meomory Statistics,虚拟内存统计)是Linux中监控内存的常用工具,它收集和显示关于**内存**,**进程**,**终端**和**分页**和**I/O阻塞**的概括信息。 + +```shell +# 每隔1秒打印一次,一共打印3次。-S指定显示单位, M代表Mb, 默认为Kb +[root@localhost ~]# vmstat -SM 1 3 +procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu----- + r b swpd free buff cache si so bi bo in cs us sy id wa st + 1 0 0 2433 2 657 0 0 132 8 77 95 1 2 97 1 0 + 0 0 0 2433 2 657 0 0 0 0 47 71 0 0 100 0 0 + 0 0 0 2433 2 657 0 0 0 0 54 72 0 0 100 0 0 +``` + +- **procs** + + - `r`:表示运行和等待CPU时间片的进程数(就是说多少个进程真的分配到CPU),**这个值如果长期大于系统CPU个数,说明CPU不足,需要增加CPU** + - `b`:表示在等待资源的进程数,比如正在等待I/O或者内存交换等 + +- **memory** + + - `swpd`:表示切换到内存交换区的内存大小,即虚拟内存已使用的大小(单位KB),**如果大于0,表示你的机器物理内存不足了,如果不是程序内存泄露的原因,那么你该升级内存了或者把耗内存的任务迁移到其他机器** + - `free`:表示当前空闲的物理内存 + - `buff`:表示缓冲大小,一般对块设备的读写才需要缓冲 + - `cache`:表示缓存大小,一般作为文件系统进行缓冲,频繁访问的文件都会被缓存,如果cache值非常大说明缓存文件比较多,如果此时io中的bi比较小,说明文件系统效率比较好 + +- **swap**:交换空间 + + 一般情况下si、so的值都为0,如果si、so的值长期不为0,则说明系统内存不足,需要增加系统内存。 + + - `si`:表示数据由磁盘读入内存;通俗的讲就是每秒从磁盘读入虚拟内存的大小,**如果这个值大于0,表示物理内存不够用或者内存泄露了,要查找耗内存进程解决掉** + - `so`:表示由内存写入磁盘,也就是由内存交换区进入内存的数据大小 + +- **io** + + 如果bi+bo的值过大,且wa值较大,则表示系统磁盘IO瓶颈。 + + - `bi`:表示由块设备读入数据的总量,即读磁盘,单位kb/s + - `bo`:表示写到块设备数据的总量,即写磁盘,单位kb/s + +- **system** + + 这两个值越大,则由内核消耗的CPU就越多。 + + - `in`:表示某一时间间隔内观测到的每秒设备终端数 + - `cs`:表示每秒产生的上下文切换次数,**这个值要越小越好,太大了,要考虑调低线程或者进程的数目** + +- **CPU(百分比)** + + - `us`:表示用户进程消耗的CPU时间比,**us值越高,说明用户进程消耗CPU时间越多。如果长期大于50%,则需要考虑优化程序或者算法** + - `sy`:表示系统内核进程消耗的CPU时间比,**一般us+sy应该小于80%,如果大于80%,说明可能存在CPU瓶颈** + - `id`:表示CPU处在空间状态的时间百分比 + - `wa`:表示IP等待所占用的CPU时间百分比,**wa值越高,说明I/O等待越严重,根据经验wa的参考值为20%,如果超过20%,说明I/O等待严重,引起I/O等待的原因可能是磁盘大量随机读写造成的,也可能是磁盘或者监控器的贷款瓶颈(主要是块操作)造成的** + + + +## I/O + +从文件系统和磁盘 I/O 的角度来说,主要性能指标,就是文件系统的使用、缓存和缓冲区的使用,以及磁盘 I/O 的使用率、吞吐量和延迟等。 + +![img](images/DevOps/7df09cbf580b688f84384e209c24c173.png)![img](images/DevOps/1477786-20201122135610356-597293017-1629438006328.png) + +![img](images/DevOps/817fec330eb2e96f1e355ad53dfa74c6.png) + +### iostat iostat用于报告中央处理器(CPU)统计信息和整个系统、适配器、tty 设备、磁盘和 CD-ROM 的输入/输出统计信息,默认显示了与vmstat相同的cpu使用信息,使用以下命令显示扩展的设备统计: @@ -956,7 +1014,7 @@ iostat 1 30 -#### pidstat +### pidstat pidstat主要用于监控全部或指定进程占用系统资源的情况。如CPU、内存、设备IO、任务切换和线程等。 @@ -987,7 +1045,7 @@ pidstat –d –p {pid} {interval} [count] -#### iotop +### iotop iotop命令是专门显示硬盘IO的命令,界面风格类似top命令,可以显示IO负载具体是由哪个进程产生的。是一个用来监视磁盘I/O使用状况的top类工具,具有与top相似的UI,其中包括PID、用户、I/O、进程等相关信息。可以以非交互的方式使用:iotop –bod interval。查看每个进程的I/O,可以使用pidstat,pidstat –d instat。 @@ -1002,9 +1060,17 @@ iotop -### Network +## Network + +从网络的角度来说,主要性能指标就是吞吐量、响应时间、连接数、丢包数等。 + +![img](images/DevOps/7aace9181112609a0621e63c13bf4088.png) + +![img](images/DevOps/1477786-20201122135828625-682254107.png) + +![img](images/DevOps/4737bd5fae25f97303f4a761f78b3419.png) -#### netstat +### netstat netstat 是一个内置工具,用于显示IP、TCP、UDP和ICMP协议相关的统计数据,一般用于检验本机各端口网络连接情况。 @@ -1047,7 +1113,7 @@ unix 1 [ ] STREAM CONNECTED 16182 @000000df -#### iftop +### iftop iftop可用来监控网卡的实时流量(可以指定网段)、反向解析IP、显示端口信息等,详细的将会在后面的使用参数中说明。 @@ -1071,7 +1137,7 @@ iftop -#### tcpdump +### tcpdump tcpdump可以用来查看网络连接的封包内容。它显示了传输过程中封包内容的各种信息。为了使得输出信息更为有用,它允许使用者通过不同的过滤器获取自己想要的信息。 @@ -1122,9 +1188,9 @@ tcpdump -i eth0 '((port 8000) and (tcp[(tcp[12]>>2):4]=0x47455420))' -nnAl -w /t -### Others +## Others -#### dstat +### dstat 该命令整合了 **vmstat、iostat、ifstat** 三种命令。同时增加了新的特性和功能可以让你能及时看到各种的资源使用情况,从而能够使你对比和整合不同的资源使用情况。通过不同颜色和区块布局的界面帮助你能够更加清晰容易的获取信息。它也支持将信息数据导出到cvs格式文件中,从而用其他应用程序打开,或者导入到数据库中。你可以用该命令来监控cpu,内存和网络状态随着时间的变化。 @@ -1191,7 +1257,7 @@ dstat -#### saidar +### saidar saidar是一个简单且轻量的系统信息监控工具。虽然它无法提供大多性能报表,但是它能够通过一个简单明了的方式显示最有用的系统运行状况数据。可以容易地看到运行时间、平均负载、CPU、内存、进程、磁盘和网络接口统计信息。 @@ -1207,7 +1273,7 @@ saidar是一个简单且轻量的系统信息监控工具。虽然它无法提 -#### Glances +### Glances **Glances** 是一个由 Python 编写,使用 **psutil** 库来从系统抓取信息的基于 curses 开发的跨平台命令行系统监视工具。 通过 Glances,我们可以监视 **CPU、平均负载、内存、网络流量、磁盘 I/O、其它处理器** 和 **文件系统** 空间的利用情况。 @@ -1254,36 +1320,6 @@ saidar是一个简单且轻量的系统信息监控工具。虽然它无法提 - - -## Statistics - -```shell -# 查看某个进程的PID -ps -ef | grep arthas-demo.jar - -# 查看java关键词的进程的数量 -ps -ef | grep java| wc -l - -# 查看线程是否存在死锁 -jstack -l - -# 统计某个进程的线程数量 -ps -efL | grep [pid] | wc -l - -# 查看某个进制有哪些线程 -ps -Lp [pid] cu - -# 统计所有的log文件中,包含Error字符的行 -find / -type f -name "*.log" | xargs grep "ERROR" - -# 统计日志文件中包含特定异常数量 -cat xxx.log | grep ** *Exception| wc -l - -# 统计log中301、302状态码的行数,$8表示第八列是状态码,可以根据实际情况更改 -awk'{print $8}' 2017-05-22-access_log|egrep '301|302'| wc -l -``` - ### GoAccess **GoAccess 是一个实时的网络日志分析器**。它能分析 apache、nginx 和 amazon cloudfront 的访问日志。它也可以将数据输出成 HTML、JSON 或 CSV 格式。它会给你一个基本的统计信息、访问量、404 页面,访客位置和其他东西。 diff --git a/Middleware.md b/Middleware.md index 8fc99cc..1fc3cf1 100644 --- a/Middleware.md +++ b/Middleware.md @@ -266,55 +266,47 @@ bitmap是一串连续的2进制数字(0或1),每一位所在的位置为 ### SDS(简单动态字符) -字符串结构使用最广泛,通常我们用于缓存登陆后的用户信息,key = userId,value = 用户信息 JSON 序列化成字符串。C 语言中字符串的获取 「MageByte」的长度,要从头开始遍历,直到 「\0」为止,Redis 作为唯快不破的男人是不能忍受的。C 语言字符串结构与 SDS 字符串结构对比图如下所示: - ![img](images/Middleware/SDS简单动态字符.png) +C 语言字符串结构与 SDS 字符串结构对比图如上所示: +- SDS 中 len 保存这字符串的长度,O(1) 时间复杂度查询字符串长度信息 +- 空间预分配:SDS 被修改后,程序不仅会为 SDS 分配所需要的必须空间,还会分配额外的未使用空间 +- 惰性空间释放:当对 SDS 进行缩短操作时,程序并不会回收多余的内存空间,而是使用 free 字段将这些字节数量记录下来不释放,后面如果需要 append 操作,则直接使用 free 中未使用的空间,减少了内存的分配 -### hash表(字典) -Redis 整体就是一个 哈希表来保存所有的键值对,无论数据类型是 5 种的任意一种。哈希表,本质就是一个数组,每个元素被叫做哈希桶,不管什么数据类型,每个桶里面的 entry 保存着实际具体值的指针。 + +### hash表(字典) ![img](images/Middleware/Redis全局hash字典.png) +Redis 整体就是一个 哈希表来保存所有的键值对,无论数据类型是 5 种的任意一种。哈希表,本质就是一个数组,每个元素被叫做哈希桶,不管什么数据类型,每个桶里面的 entry 保存着实际具体值的指针。 + 整个数据库就是一个全局哈希表,而哈希表的时间复杂度是 O(1),只需要计算每个键的哈希值,便知道对应的哈希桶位置,定位桶里面的 entry 找到对应数据,这个也是 Redis 快的原因之一。 **那 Hash 冲突怎么办?** -当写入 Redis 的数据越来越多的时候,哈希冲突不可避免,会出现不同的 key 计算出一样的哈希值。Redis 通过链式哈希解决冲突:也就是同一个 桶里面的元素使用链表保存。但是当链表过长就会导致查找性能变差可能,所以 Redis 为了追求快,使用了两个全局哈希表。用于 rehash 操作,增加现有的哈希桶数量,减少哈希冲突。开始默认使用 hash 表 1 保存键值对数据,哈希表 2 此刻没有分配空间。当数据越来多触发 rehash 操作,则执行以下操作: - -1. 给 hash 表 2 分配更大的空间 -2. 将 hash 表 1 的数据重新映射拷贝到 hash 表 2 中 -3. 释放 hash 表 1 的空间 - -值得注意的是,将 hash 表 1 的数据重新映射到 hash 表 2 的过程中并不是一次性的,这样会造成 Redis 阻塞,无法提供服务。而是采用了渐进式 rehash,每次处理客户端请求的时候,先从 hash 表 1 中第一个索引开始,将这个位置的 所有数据拷贝到 hash 表 2 中,就这样将 rehash 分散到多次请求过程中,避免耗时阻塞。 +当写入 Redis 的数据越来越多的时候,哈希冲突不可避免,会出现不同的 key 计算出一样的哈希值。Redis 通过链式哈希解决冲突:也就是同一个 桶里面的元素使用链表保存。但是当链表过长就会导致查找性能变差可能,所以 Redis 为了追求快,使用了两个全局哈希表。用于 rehash 操作,增加现有的哈希桶数量,减少哈希冲突。开始默认使用 hash 表 1 保存键值对数据,哈希表 2 此刻没有分配空间。 ### linkedList(双端列表) -Redis List 数据类型通常被用于队列、微博关注人时间轴列表等场景。不管是先进先出的队列,还是先进后出的栈,双端列表都很好的支持这些特性。Redis 的链表实现的特性可以总结如下: - -- **双端**:链表节点带有 prev 和 next 指针,获取某个节点的前置节点和后置节点的复杂度都是 O(1) -- **无环**:表头节点的 prev 指针和表尾节点的 next 指针都指向 NULL,对链表的访问以 NULL 为终点 -- **带表头指针和表尾指针**:通过 list 结构的 head 指针和 tail 指针,程序获取链表的表头节点和表尾节点的复杂度为 O(1) -- **带链表长度计数器**:程序使用 list 结构的 len 属性来对 list 持有的链表节点进行计数,程序获取链表中节点数量的复杂度为 O(1) -- **多态**:链表节点使用 void* 指针来保存节点值,并且可以通过 list 结构的 dup、free、match 三个属性为节点值设置类型特定函数,所以链表可以用于保存各种不同类型的值 - -后续版本对列表数据结构进行了改造,使用 quicklist 代替了 ziplist 和 linkedlist。quicklist 是 ziplist 和 linkedlist 的混合体,它将 linkedlist 按段切分,每一段使用 ziplist 来紧凑存储,多个 ziplist 之间使用双向指针串接起来。 - ![quicklist](images/Middleware/quicklist.png) -这也是为何 Redis 快的原因,不放过任何一个可以提升性能的细节。 +后续版本对列表数据结构进行了改造,使用 quicklist 代替了 ziplist 和 linkedlist。quicklist 是 ziplist 和 linkedlist 的混合体,它将 linkedlist 按段切分,每一段使用 ziplist 来紧凑存储,多个 ziplist 之间使用双向指针串接起来。这也是为何 Redis 快的原因,不放过任何一个可以提升性能的细节。 ### zipList压缩列表 -压缩列表是 List 、hash、 sorted Set 三种数据类型底层实现之一。当一个列表只有少量数据的时候,并且每个列表项要么就是小整数值,要么就是长度比较短的字符串,那么 Redis 就会使用压缩列表来做列表键的底层实现。ziplist 是由一系列特殊编码的连续内存块组成的顺序型的数据结构,ziplist 中可以包含多个 entry 节点,每个节点可以存放整数或者字符串。ziplist 在表头有三个字段 zlbytes、zltail 和 zllen,分别表示列表占用字节数、列表尾的偏移量和列表中的 entry 个数;压缩列表在表尾还有一个 zlend,表示列表结束。 +![ZipList压缩列表](images/Middleware/ZipList压缩列表.png) + +压缩列表是 List 、hash、 sorted Set 三种数据类型底层实现之一。当一个列表只有少量数据的时候,并且每个列表项要么就是小整数值,要么就是长度比较短的字符串,那么 Redis 就会使用压缩列表来做列表键的底层实现。 + +ziplist 是由一系列特殊编码的连续内存块组成的顺序型的数据结构,ziplist 中可以包含多个 entry 节点,每个节点可以存放整数或者字符串。ziplist 在表头有三个字段 zlbytes、zltail 和 zllen,分别表示列表占用字节数、列表尾的偏移量和列表中的 entry 个数;压缩列表在表尾还有一个 zlend,表示列表结束。 ```go struct ziplist { @@ -326,25 +318,23 @@ struct ziplist { } ``` -![ZipList压缩列表](images/Middleware/ZipList压缩列表.png) - 如果我们要查找定位第一个元素和最后一个元素,可以通过表头三个字段的长度直接定位,复杂度是 O(1)。而查找其他元素时,就没有这么高效了,只能逐个查找,此时的复杂度就是 O(N)。 ### skipList(跳跃表) -sorted set 类型的排序功能便是通过「跳跃列表」数据结构来实现。跳跃表(skiplist)是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。跳跃表支持平均 O(logN)、最坏 O(N)复杂度的节点查找,还可以通过顺序性操作来批量处理节点。跳表在链表的基础上,增加了多层级索引,通过索引位置的几个跳转,实现数据的快速定位,如下图所示: - ![skipList跳跃表](images/Middleware/skipList跳跃表.png) -当需要查找 40 这个元素需要经历 三次查找。 +sorted set 类型的排序功能便是通过「跳跃列表」数据结构来实现。跳跃表(skiplist)是一种有序数据结构,它通过在每个节点中维持多个指向其他节点的指针,从而达到快速访问节点的目的。 + +跳跃表支持平均 O(logN)、最坏 O(N)复杂度的节点查找,还可以通过顺序性操作来批量处理节点。跳表在链表的基础上,增加了多层级索引,通过索引位置的几个跳转,实现数据的快速定位。 ### 整数数组(intset) -当一个集合只包含整数值元素,且这个集合的元素数量不多时,Redis 就会使用整数集合作为集合键的底层实现。结构如下: +当一个集合只包含整数值元素,并且这个集合的元素数量不多时,Redis 就会使用整数集合作为集合键的底层实现,节省内存。结构如下: ```go typedef struct intset{ diff --git a/images/Architecture/640.webp b/images/Architecture/640.webp new file mode 100644 index 0000000..7997539 Binary files /dev/null and b/images/Architecture/640.webp differ diff --git a/images/Architecture/消息队列丢失消息.png b/images/Architecture/消息队列丢失消息.png new file mode 100644 index 0000000..3a0fdc1 Binary files /dev/null and b/images/Architecture/消息队列丢失消息.png differ diff --git a/images/Architecture/消费者丢失消息.png b/images/Architecture/消费者丢失消息.png new file mode 100644 index 0000000..c18e8fb Binary files /dev/null and b/images/Architecture/消费者丢失消息.png differ diff --git a/images/Architecture/生产者存放消息的过程中丢失消息.jpg b/images/Architecture/生产者存放消息的过程中丢失消息.jpg new file mode 100644 index 0000000..7997539 Binary files /dev/null and b/images/Architecture/生产者存放消息的过程中丢失消息.jpg differ diff --git a/images/DevOps/1477786-20201122134301506-441066821.png b/images/DevOps/1477786-20201122134301506-441066821.png new file mode 100644 index 0000000..df3d32e Binary files /dev/null and b/images/DevOps/1477786-20201122134301506-441066821.png differ diff --git a/images/DevOps/1477786-20201122135426680-1563483565.png b/images/DevOps/1477786-20201122135426680-1563483565.png new file mode 100644 index 0000000..dc59d62 Binary files /dev/null and b/images/DevOps/1477786-20201122135426680-1563483565.png differ diff --git a/images/DevOps/1477786-20201122135610356-597293017-1629438006328.png b/images/DevOps/1477786-20201122135610356-597293017-1629438006328.png new file mode 100644 index 0000000..2641f15 Binary files /dev/null and b/images/DevOps/1477786-20201122135610356-597293017-1629438006328.png differ diff --git a/images/DevOps/1477786-20201122135610356-597293017.png b/images/DevOps/1477786-20201122135610356-597293017.png new file mode 100644 index 0000000..2641f15 Binary files /dev/null and b/images/DevOps/1477786-20201122135610356-597293017.png differ diff --git a/images/DevOps/1477786-20201122135828625-682254107.png b/images/DevOps/1477786-20201122135828625-682254107.png new file mode 100644 index 0000000..ef9c2ed Binary files /dev/null and b/images/DevOps/1477786-20201122135828625-682254107.png differ diff --git a/images/DevOps/1657486-20200110163906854-1971599861.png b/images/DevOps/1657486-20200110163906854-1971599861.png new file mode 100644 index 0000000..e57af17 Binary files /dev/null and b/images/DevOps/1657486-20200110163906854-1971599861.png differ diff --git a/images/DevOps/4737bd5fae25f97303f4a761f78b3419.png b/images/DevOps/4737bd5fae25f97303f4a761f78b3419.png new file mode 100644 index 0000000..908d071 Binary files /dev/null and b/images/DevOps/4737bd5fae25f97303f4a761f78b3419.png differ diff --git a/images/DevOps/4dc3e5aba96c56ac1b3e8d51611934dd.png b/images/DevOps/4dc3e5aba96c56ac1b3e8d51611934dd.png new file mode 100644 index 0000000..0f404e1 Binary files /dev/null and b/images/DevOps/4dc3e5aba96c56ac1b3e8d51611934dd.png differ diff --git a/images/DevOps/7aace9181112609a0621e63c13bf4088.png b/images/DevOps/7aace9181112609a0621e63c13bf4088.png new file mode 100644 index 0000000..1f19b71 Binary files /dev/null and b/images/DevOps/7aace9181112609a0621e63c13bf4088.png differ diff --git a/images/DevOps/7df09cbf580b688f84384e209c24c173.png b/images/DevOps/7df09cbf580b688f84384e209c24c173.png new file mode 100644 index 0000000..3e2b328 Binary files /dev/null and b/images/DevOps/7df09cbf580b688f84384e209c24c173.png differ diff --git a/images/DevOps/817fec330eb2e96f1e355ad53dfa74c6.png b/images/DevOps/817fec330eb2e96f1e355ad53dfa74c6.png new file mode 100644 index 0000000..90137d0 Binary files /dev/null and b/images/DevOps/817fec330eb2e96f1e355ad53dfa74c6.png differ diff --git a/images/DevOps/9ca30729b6120a06dff8d3c72a93f8e2.png b/images/DevOps/9ca30729b6120a06dff8d3c72a93f8e2.png new file mode 100644 index 0000000..5826eb7 Binary files /dev/null and b/images/DevOps/9ca30729b6120a06dff8d3c72a93f8e2.png differ diff --git a/images/DevOps/b4e930f089487cc2431f3f2f067f0425.png b/images/DevOps/b4e930f089487cc2431f3f2f067f0425.png new file mode 100644 index 0000000..1cf5306 Binary files /dev/null and b/images/DevOps/b4e930f089487cc2431f3f2f067f0425.png differ diff --git a/images/DevOps/d474b437af17bd1d35eb6f64b520a8ac.png b/images/DevOps/d474b437af17bd1d35eb6f64b520a8ac.png new file mode 100644 index 0000000..060b5cd Binary files /dev/null and b/images/DevOps/d474b437af17bd1d35eb6f64b520a8ac.png differ