内存泄露排查OOM 导致被杀较为明显的内存泄漏不太明显的内存泄漏进程异常排查查看系统级别是否运行异常测试网络连通性查看进程级别是否运行异常进程后台运行删除 - 开头文件查看系统信息CPUTCP 协议TCP 连接建立TCP 连接释放HTTP 协议wrk: HTTP 压力测试wrk的全局属性wrk 的全局方法启动阶段运行阶段结束阶段wrk 使用手册示例 1示例 2示例 3检测服务器是否支持断点续传GDB 小技巧基本操作调试 coredumpVIM 小技巧Git 小技巧基本操作git stashgit tag合并分支到主干删除远程分支查看历史提交信息仓库迁移合并多次提交设置代理git pull/push 记住密码github 同步 fork 仓库github 提交 PRYUM 小技巧查询删除Docker 小技巧镜像标签由 Dockerfile 构建镜像容器由容器构建镜像将镜像推送到 DockerHub端口映射挂载目录解决无法运行 systemctl机器时间、硬件时钟网络测速SSH 机器互信(免密登陆)PSSH 批量操作SSH 禁用超时跳板机 Jumpserver 上传/下载文件上传文件 rz下载文件 szMySQL 小技巧MySQL 命令行模式显示查询记录MySQL 清理控制台MySQL 查看库、表结构MySQL 随机排序快捷选择 MySQL 实例条件插入timestamp 字段查询时间相关函数查询 utc 时间戳、utc 日期、utc 时间、now()now() 与 sysdate() 异同date_add 函数INSERT INTO SELECT 语句查看表创建时间三目表达式between ... and ...IFNULL条件更新查询显示行号删除重复记录替换字段数据备份与恢复Golang 小技巧判断 goproxy 是否缓存了某个 Go 模块的特定版本查看每个依赖项的完整 HTTP 请求路径Redis 小技巧批量删除 keyNGINX 基础配置配置静态资源使用 alias 重定义路径使用 root 指定前缀Location 匹配规则语法规则匹配过程示例详解location @name 使用URL 尾部的 /配置静态资源实践原则参考资料NGINX 性能优化高层的配置Events 模块NGINX 配置文件错误检查NGINX 实战同时代理前端和后台接口代理 websocketBash 共享屏幕/录制屏幕共享终端录制屏幕与回放java 反编译CFRbrew 安装指定版本的库C++调用 golang 动态库使用 frp 实现 Windows 远程桌面连接刷新 DNS 缓存解决 godaddy 根域名 @ 不支持 cnameCentOS 7 升级内核


内存泄露排查

OOM 导致被杀

利用 dmesg 查看

较为明显的内存泄漏

通过系统自带的命令持续地观察进程内存的占用情况,即可发现有明显内存泄漏的进程;更进一步,当进程运行一段时间导致系统内存耗尽,将会被操作系统杀掉。

不太明显的内存泄漏

进程异常排查

查看系统级别是否运行异常

测试网络连通性

查看进程级别是否运行异常

进程后台运行

删除 - 开头文件

加入当前目录前缀即可,例如

查看系统信息

CPU

TCP 协议

TCP 连接建立

在 TCP/IP 协议中,TCP 协议提供可靠的连接服务,采用三次握手建立一个连接。

为什么要三次握手?

防止失效的连接请求突然传到服务器端,让服务器端误认为要建立连接。

TCP 连接释放

在 TCP/IP 协议中,TCP 协议提供可靠的连接服务,采用四次挥手释放一个连接。

为什么 Client 进入 TIME-WAIT 后必须等待 2 MSL

报文段最大生存时间 MSL(Maximum Segment Lifetime),它是任何报文段被丢弃前在网络内的最长时间,实现中的常用值是 30秒,1 分钟,或 2 分钟

HTTP 协议

wrk: HTTP 压力测试

wrk的全局属性

wrk 的全局方法

启动阶段

在脚本文件中实现 setup 方法,wrk 就会在测试线程已经初始化但还没有启动的时候调用该方法。wrk 会为每一个测试线程调用一次 setup 方法,并传入代表测试线程的对象 thread 作为参数。setup 方法中可操作该thread 对象,获取信息、存储信息、甚至关闭该线程。

thread提供了 1 个属性,3 个方法

运行阶段

init 由测试线程调用,只会在进入运行阶段时,调用一次。支持从启动 wrk 的命令中,获取命令行参数; delay 在每次发送 request 之前调用,如果需要 delay,那么 delay 相应时间; request 用来生成请求;每一次请求都会调用该方法,所以注意不要在该方法中做耗时的操作; reponse 在每次收到一个响应时调用;为提升性能,如果没有定义该方法,那么 wrk 不会解析 headers 和 body。

结束阶段

该方法在整个测试过程中只会调用一次,可从参数给定的对象中,获取压测结果,生成定制化的测试报告。

wrk 使用手册

示例 1

启动 4 个线程,创建 100 个连接,持续 10s,请求百度主页(支持 HTTP/HTTPS

结果分析:

示例 2

每个线程要先进行认证,认证之后获取 token 以进行压测。在没有token的情况下,先访问 /authenticate 认证。认证成功后,读取 token 并替换 path 为 /resource。

示例 3

启动 4 个线程,创建 100 个连接,持续 10s,每个请求发送不同的数据

脚本内容如下所示

执行压测用例

检测服务器是否支持断点续传

利用 curl 发起请求,响应报文中包含 Content-Range,则表明服务器支持断点续传。

GDB 小技巧

基本操作

调试 coredump

VIM 小技巧

快捷键(命令)功能
:%s/foo/bar/gc全文替换时带确认,即,对于任何一个匹配项,需要确认是否替换
:%s/foo/bar/g全文替换时(不待确认)
:s/foo/bar/g当前行替换(不带确认)
:'<,'>s/foo/bar/g选定范围内替换(不带确认),在 Visual 模式下选择区域后输入 :,Vim 即可自动补全为 :'<,'>。例如,:2,10/foo/bar/g 替换第 2~10 行所有匹配项
:.,+2s/foo/bar/g当前行和接下来的 2 行替换(不带确认)
ctrl+w s上下(垂直)分割当前打开的文件
ctrl+w v左右(水平)分割当前打开的文件
ctrl+w c关闭当前窗口,对应 :close。最后一个窗口不能使用 close 关闭,使用 close 只是暂时关闭窗口,其内容还在缓存中
ctrl+w q关闭当前窗口,对应 :quit。与 close 不同之处在于永久关闭窗口,因此可关闭最后一个打开的窗口
ctrl+w ctrl+w连续两次 ctrl+w,切换窗口
ctrl+w h/j/k/lctrl+w 配合 h/j/k/l 或者上下左右方向键切换窗口
:new filename横向切割窗口
:split filename横向切割窗口,可简写 :sp filename
:vsplit filename纵向切割窗口,可简写为 :vsp filename
:set list进入 List Mode,显示 tab、空格。TAB 键显示为 ^I,$ 显示在每行的结尾,表示换行;空格仍然显示为空格
:set nolist退出 List Mode
x, X在一行字当中,x 为向后删除一个字符,X 为向前删除一个字符
nxn 为数字,连续向后删除 n 个字符
dd删除游标所在的那一整行
nddn 为数字,连续删除游标所在的向下 n 行
d1G删除从第一行到游标所在行
dG删除游标到最后一行
d0删除第一个字符到游标处所有字符
d$删除游标到行末最后一个字符
yy复制游标所在那一行。
同理,nyy,y1G,yG,y0,y$ 逻辑与删除一致
p, P粘贴。p 为将已复制的内容粘贴到游标下一行,P 为将已复制的内容粘贴到游标上一行
J将游标所在行与下一行的内容结合成同一行
u复原(undo)前一个动作
ctrl+r重做(redo)上一个动作
gg跳转到第一行
G跳转到最后一行
nGn 位数字,跳转到第 n 行

Git 小技巧

基本操作

git stash

默认情况下,git stash 缓存文件的策略如下:

会缓存下列文件

不会缓存以下文件

使用 -u 或者 --include-untracked 可以 stash untracked 的文件

使用 -a 或者 --all 命令可以 stash 当前目录下的所有修改

git tag

合并分支到主干

删除远程分支

推送一个空分支到远程分支,其实就相当于删除远程分支:

查看历史提交信息

仓库迁移

合并多次提交

  1. 将头部指针指向要合并的第一个提交的前一个提交

  1. 重新提交

设置代理

  1. 设置代理

  1. 取消代理

git pull/push 记住密码

cache 是存储在内存中,可以设定有效时间但是时间过去后,将会失效;store 是存储在磁盘上,不过用户名和密码是明文存储的

github 同步 fork 仓库

以同步 master 分支为例,其他分支同理

  1. 克隆已 fork 的项目到本地

  1. 添加远程原始仓库

查看远程仓库信息 git remote -v

移除远程仓库 git remote remove upstream

  1. 同远程原始仓库同步

git pullgit pull upstream master 的区别,前者表示拉取自己远程仓库(默认为 master 分支),后者表示拉取外部的上游分支

  1. 同步之后推送到 githubfork 的项目

github 提交 PR

一般地,为每一个 PR 创建一个分支

  1. 将远程分支(待提交 PR 的目标仓库的目标分支)检出作为本地分支 <local branch>

  1. 将某次(或多次)提交 cherry-pick 到本地分支 <local branch>

  1. 将本地分支推到自己的远程仓库

  1. github 上面基于 <remote branch>upstream/master 提交 PR

YUM 小技巧

查询

删除

Docker 小技巧

镜像

标签

由 Dockerfile 构建镜像

容器

通过 inspect 查看容器挂载目录、启动命令等

由容器构建镜像

将镜像推送到 DockerHub

端口映射

-P 随机映射一个端口到内部容器开放的端口

-p 使用 IP:HostPort:ContainerPort 格式指定映射使用一个特定的地址

挂载目录

格式:-v <host-dir>:<container-dir>

容器目录必须使用绝对路径,目录不存在则自动创建

宿主机目录建议使用绝对路径,相对路径并非相对当前目录而言,而是相对 /var/lib/docker/volumes/

解决无法运行 systemctl

构建容器,使用如下指令即可

机器时间、硬件时钟

网络测速

  1. 安装 speedtest

  1. 测速

使用 speedtest 或者 speedtest-cli 命令测试,更精确测速,可以选择指定服务器

SSH 机器互信(免密登陆)

目标:client 被 server 信任,即,client 可以通过免密 ssh 登陆 server。

  1. client 产生公钥

  1. 将步骤 1 中产生的 id_rsa.pub 拷贝并追加到 server 已授权 key 文件中

  1. 重启 server 端 ssh 服务

PSSH 批量操作

  1. 目标机器均已经对操作机器做互信

  2. 通过 PSSH 批量操作,如下所示

SSH 禁用超时

目标:SSH 空闲之后,默认断掉,每次需要重连太过麻烦,可以修改 SSH 服务端设置禁用超时;也可以客户端定时发送心跳包保活。

  1. 在 /etc/ssh/sshd_config 添加/修改如下配置项

  1. 重启 server 端 ssh 服务

在客户端配置后,就会有反空闲设置,即每 30s 会自动和服务端做一次确认。如果在 Windows 下使用 SecureCRT,如下操作即可

如果在 Windows 下使用 Putty,putty -> Connection -> Seconds between keepalives ( 0 to turn off ),默认为 0,改为30

跳板机 Jumpserver 上传/下载文件

需求:linux 服务器大多是通过 ssh 客户端来进行远程的登陆和管理,使用跳板机 Jumpserver,传输文件是个基础需求,可以借助 rz/sz 实现

限制:rz/sz 只支持对文件(不支持文件夹)操作

上传文件 rz

下载文件 sz

MySQL 小技巧

MySQL 命令行模式显示查询记录

MySQL 清理控制台

MySQL 查看库、表结构

MySQL 随机排序

快捷选择 MySQL 实例

  1. 创建脚本 xdb.sh

  1. chmod +x xdb.sh

  2. 使用 ./xdb.sh log 即可快捷登陆 log.lsb.com 的数据库 log

条件插入

场景:先根据条件判断某条记录是否存在,不存在则插入;存在即跳过。

语法:insert into table(column1, column2, ..., columnN) select value1, value2, value3, ..., valueN from dual where not exists (condition clause)

timestamp 字段查询

场景一:查询某个时间范围的数据

场景二:查询某一天数据

时间相关函数

查询 utc 时间戳、utc 日期、utc 时间、now()

now() 与 sysdate() 异同

date_add 函数

INSERT INTO SELECT 语句

查看表创建时间

三目表达式

between ... and ...

SQL 中使用 between ... and ...,查询条件是闭区间,且上下限调换不等价,如下所示

between a and b => x ∈ [a, b] => x ≥ a && x ≤ b

where id between a and b => where id >= a and id <= b

所以,在处理起始终止范围查询业务逻辑时,SQL 中使用 between ... and ... 一定需要处理好上下限。即,前端、后端都应该确保上下限 a ≤ b

IFNULL

IFNULL() 函数用于判断第一个表达式是否为 NULL,如果为 NULL 则返回第二个参数的值,如果不为 NULL 则返回第一个参数的值。

条件更新

查询显示行号

删除重复记录

只保留第一条 t1.id > t2.id

替换字段

UPDATE 表名 SET 字段名=replace(字段名, ‘被替换字符串’, ‘用来替换的字符串’) ;

数据备份与恢复

Golang 小技巧

判断 goproxy 是否缓存了某个 Go 模块的特定版本

如果缓存中存在该模块版本,会返回模块的元信息(JSON 格式)

如果缓存中不存在该模块版本,会返回 HTTP 404 错误

查看每个依赖项的完整 HTTP 请求路径

参数说明

GODEBUG=http2debug=2:启用 HTTP/2 的调试日志,会显示完整的 HTTP 请求和响应路径。

GOPROXY:指定 goproxy URL,可以是官方的或自定义的代理服务。

输出结果

Redis 小技巧

批量删除 key

NGINX 基础配置

配置静态资源

使用 alias 重定义路径

静态资源如下所示

Nginx 配置如下

测试结果

使用 root 指定前缀

静态资源如下所示

Nginx 配置如下

测试结果

Location 匹配规则

语法规则

location 为关键字,后面跟着可选的修饰符,后面是要匹配的字符,花括号中是要执行的操作

匹配过程

匹配开始前,对请求的 url 序列化。例如,对 %xx 等字符进行解码,去除 url 中多个相连的 /,解析 url...

location 有两种表示形式,一种是使用前缀字符,一种是使用正则。如果是正则的话,前面有 ~~* 修饰符

具体的匹配过程如下:

  1. 首先先检查使用前缀字符定义的 location,选择最长匹配的项并记录下来

  2. 如果找到了精确匹配的 location,也就是使用了 = 修饰符的 location,结束查找,使用它的配置

  3. 按顺序查找使用正则定义的 location,如果匹配则停止查找,使用它定义的配置

  4. 如果没有匹配的正则 location,则使用前面记录的最长匹配前缀字符 location

示例详解

假设有如下配置文件

请求 / 精准匹配 A,不再往下查找

请求 /index.html 匹配 B。首先查找匹配的前缀字符,找到最长匹配是配置 B,接着又按照顺序查找匹配的正则。结果没有找到,因此使用先前标记的最长匹配,即配置 B

请求 /user/index.html 匹配 C。首先找到最长匹配 C,由于后面没有匹配的正则,所以使用最长匹配 C 请求 /user/1.jpg 匹配E。首先进行前缀字符的查找,找到最长匹配项 C,继续进行正则查找,找到匹配项 E。因此使用 E

请求 /images/1.jpg匹配 D。首先进行前缀字符的查找,找到最长匹配 D。但是,特殊的是它使用了 ^~ 修饰符,不再进行接下来的正则的匹配查找,因此使用 D。这里,如果没有前面的修饰符,其实最终的匹配是 E

请求 /documents/about.html 匹配 B。因为 B 表示任何以/开头的 URL 都匹配。在上面的配置中,只有 B 能满足,所以匹配 B

location @name 使用

@用来定义一个命名 location。主要用于内部重定向,不能用来处理正常的请求(该块不能被外部 Client 所访问,只能被内部配置指令所访问,比如 try_files、error_page)

命名 location 中不能再嵌套其它的命名 location

上例中,当尝试访问 uri 找不到对应的文件就重定向到我们自定义的命名 location(此处为custom)

URL 尾部的 /

配置静态资源

静态资源有两种配置模式,目录匹配或后缀匹配,任选其一或搭配使用

实践原则

参考资料

NGINX 性能优化

nginx 默认的配置 /etc/nginx/nginx.conf,当然,一般 nginx.conf 会引用其他目录的配置文件,例如目录 conf.d,如下讨论主要基于 nginx.conf 全局配置。

NGINX 官方配置说明:http://nginx.org/en/docs/ngx_core_module.html

高层的配置

nginx.conf 文件中,nginx 中有少数的几个高级配置在模块部分之上。

Events 模块

events 模块中包含 nginx 中所有处理连接的设置。

工作进程同时打开的连接数限制也由系统的可用 socket 连接数限制,所以设置不切实际的高没什么好处。

NGINX 配置文件错误检查

使用 -t 检测配置文件无误,然后重启服务即可 nginx -s reload

NGINX 实战

同时代理前端和后台接口

  1. / 拦截所有请求,首先定位到前端页面,如果前端页面不存在,则跳转至 @routerback 路由

  2. @routerback 路由反向代理至后台服务接口

后台服务监听 8080 端口

代理 websocket

服务端使用 https,则 websocket 使用 wss

客户端使用 ws 或者 wss 访问即可

Bash 共享屏幕/录制屏幕

共享终端

录制屏幕与回放

java 反编译

CFR

下载地址:http://www.benf.org/other/cfr/

brew 安装指定版本的库

C++调用 golang 动态库

  1. 待生成动态库的 .go

  1. 编译生成动态库

生成 sdk.dll 和头文件 sdk.h

  1. C++ 调用动态库

  1. 编译生成可执行程序

生成可执行程序 a.exe

使用 frp 实现 Windows 远程桌面连接

前置条件:

  1. 安装 frps

frp 服务器端搭建

作为服务器端,你只需要关心 2 个文件:

其中 frps 是服务端运行程序,frps.ini 是配置文件。frps.ini 配置如下

这里主要是配置了绑定的端口(17000),控制面板的端口(17500),token(会在客户端用到),控制面板的 user 用户名和 pwd 密码。

运行 frps

访问控制面板,如下

  1. 安装 frpc

作为客户端端,你只需要关心 2 个文件:

其中 frpc 是客户端运行程序,frpc.ini 是配置文件。frpc.ini 配置如下

“server_addr” 是服务端 IP 地址,填入即可,“server_port” 为服务器端口,即 bind_port 的值,“token” 是你在服务器上设置的连接口令。

这里用到了 2 个自定义规则,一个是 rdp,一个是 smb:

其中,remote_port 对应该客户端某项服务通过服务端暴露到公网的端口。例如,上述配置中 RDP 服务,本地端口 3389,暴露在外网的端口为 17001,即,最终远程桌面连接地址为:<服务端 IP>:<17001>

运行 frpc

同时,服务端也可以看到对应的连接信息

同时,控制面板也可以看到对应的连接信息

  1. 确保目标机器开启 Windows 远程桌面连接

  2. 使用者从自己电脑运行远程桌面连接客户端,即可通过 <服务端 IP>:<17001> 连接目标机器

刷新 DNS 缓存

解决 godaddy 根域名 @ 不支持 cname

背景:aws lb 使用动态 ip,无法在 godaddy 中配置根域名的 @ 解析,godaddy 根域名 @ 解析只支持 ip 不支持 cname,可以借助 aws route 53 进行托管解决。

进到 route 53 的菜单,创建托管区域

在这里插入图片描述

创建的时候选择公有(因为是外部开放的域名)

创建完毕之后会有下面截图的四个 NS 值

在这里插入图片描述

将其保存下来,后续填写到 godaddy

进入到 godaddy 管理控制台,然后进入 Domain 中,选择需要托管的域名。点击进入后,选择 Manage DNS 开始设置

在这里插入图片描述

可以看到,上面红色标记是你域名解析记录,下面红色标记是可以更改解析服务,选择点击 change:选择使用自己的解析服务

在这里插入图片描述

在这里插入图片描述

这里将刚才 aws 生成的 NS 的四个记录给填上,保存,等 DNS 解析生效即可。

CentOS 7 升级内核

  1. 查看当前内核版本

  1. 安装 yum 源

ELRepo 仓库是基于社区的用于企业级 Linux 仓库,提供对 RedHat Enterprise (RHEL) 和 其他基于 RHEL的 Linux 发行版(CentOS、Scientific、Fedora 等)的支持。 ELRepo 聚焦于和硬件相关的软件包,包括文件系统驱动、显卡驱动、网络驱动、声卡驱动和摄像头驱动等。

导入ELRepo仓库的公共密钥

安装ELRepo仓库的yum源

  1. 查看可用的系统内核包

可以看到 4.4 和 4.18 两个版本

  1. 安装最新版本内核

--enablerepo 选项开启 CentOS 系统上的指定仓库。默认开启的是 elrepo,这里用 elrepo-kernel 替换。

  1. 设置 grub2

内核安装好后,需要设置为默认启动选项并重启后才会生效

服务器上存在4 个内核,我们要使用 4.18 这个版本,可以通过 grub2-set-default 0 命令或编辑 /etc/default/grub 文件来设置

方法1:通过 grub2-set-default 0 命令设置

其中 0 是上面查询出来的可用内核

方法二:编辑 /etc/default/grub 文件

设置 GRUB_DEFAULT=0,通过上面查询显示的编号为 0 的内核作为默认内核

  1. 验证

  1. 删除旧内核(可选)

查看系统中全部的内核

方法一:yum remove 删除旧内核的 RPM 包

方法二:yum-utils` 工具

如果安装的内核不多于 3 个,yum-utils 工具不会删除任何一个。只有在安装的内核大于 3 个时,才会自动删除旧内核。

安装 yum-utils

删除旧版本