有用的 shell&vim 命令

shell 相关

工作中,总会碰到一些『乍一看处理起来巨麻烦』的问题,特别是一些文本处理类的,但事实上只要能合理巧妙的运用 shell 命令,就能迅速的得到想要的答案,省时又省力。本文将记录下这些有用的 shell 命令,并持续更新。PS: 这里给出的方案不一定是最佳,如果有更好的方案,请留言指出:)

文本处理类

假设请求日志格式为:10.18.122.28 - - [01/Apr/2017:08:15:55 +0000] "GET /sug?channel=type_map&word=%E5%8C%97%E4%BA%AC HTTP/1.1" 200 1508 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36" "-" -0.023

1. 怀疑有坏人在刷请求,如何快速定位到对应的一批 ip。

➜ tail -f access.log | awk '{print $1}' > t.txt
先将 ip 信息先收集到单独的文件中,可减少计算量
➜ cat t.txt | sort | uniq -c | sort -nr | head -10
将结果排序|去重并记录条数|倒序|取前十条。

2. web服务器负载异常,想确认是否是 qps 过高导致。

➜ tail -f access.log | grep "\"GET " | awk '{print $4}' | uniq -c
找到请求时间戳|计算次数,也可以查到某个接口的 qps,grep 到那个接口就行。不过这样会有一个小问题,如果日志中的时间不是增量,就会有重复的情况,但基本能得到一个粗略的结果。

网络系统类

1. 查看系统最占用资源的进程

ps aux | head -1;ps aux | grep -v PID | sort -rn -k +3 | head # CPU
ps aux | head -1;ps aux | grep -v PID | sort -rn -k +4 | head # 内存
其实就是将进程的按某列倒序排序而已,友情提示:ps 查看的是进程启动以来的平均CPU利用率,并不反应实时的。

查找类

1. 提取文件名&目录名

# 1. 使用 ${}
➜  ~  var=/Users/itsmikej/zsh_ext.sh.tar.gz
➜  ~  echo ${var%%.*}
/Users/itsmikej/zsh_ext
➜  ~  echo ${var%/*}
/Users/itsmikej
➜  ~  echo ${var#*.}
sh.tar.gz
➜  ~  echo ${var##*.}
gz
➜  ~  echo ${var##*/}
zsh_ext.sh.tar.gz
# 2. 使用 basename 和 dirname
➜  ~  echo $(dirname $var)
/Users/itsmikej
➜  ~  echo $(basename $var)
zsh_ext.sh.tar.gz

关于 ${}
#:表示从左边算起第一个
%:表示从右边算起第一个
##:表示从左边算起最后一个
%%:表示从右边算起最后一个
换句话来说,#总是表示左边算起,%总是表示右边算起。
:表示要删除的内容
via:http://blog.csdn.net/ljianhui/article/details/43128465

常用数据结构&语法

......

vim 相关

普通模式

  • * 查找当前目标单词(:set hls 高亮),选中之后可以执行 cw n 批量修改。
  • b (begin)移动到单词的开头
  • e (end)移动到单词的最后
  • x 删除当前字符
  • d{motion} 删除,dd行,dl字符,daw(delete a word)单词,dap段落。(dw, db, de, dw)
  • f{char} 跳转
  • c{motion} 修改, cw 删除当前选中单词,并切换到插入模式
  • y{motion} 复制
  • g 切换大小写,g~反转,gU转大写,gu转小写
  • < > 缩进

可视模式

  • v 进入面向字符的可视模式
  • V 进入面向行的可视模式
  • ctrl+v 进入面向列块的可视模式
  • gv 重选上次的高亮选区
  • o 返回起始的选中位置

选中内容之后,就能做一些有用的操作了,比如

多行缩进:Vj 选中行,然后 >. 缩进
列操作:ctrl+v 3j 选中列, c|I|d 操作,esc 所有选中项执行该修改

......

TCP流量控制和拥塞控制

流量控制

利用窗口滑动窗口控制流量

流量控制

  • 死锁问题
  • 提升传输效率 - Nagle算法(缓存应用进程的数据,一并发送)
  • Silly window syndrome(接收方缓存已满,但每次应用进程只读取一个字节

总的原则就是:发送方不要发送很小的报文,同时接收方也不要刚有一点空间就将窗口告知发送方

拥塞控制

  • 慢启动(slowstart)
  • 拥塞避免(congestion avoidance)
  • 快重传(fast retransmit)
  • 快恢复(fast recovery)

拥塞控制

TCP滑动窗口实现

案例

假设数据流向是A到B。

构造发送窗口

此时A收到B发过来的确认报文段,窗口是20,确认号是31,根据这两个数据构造出A的发送窗口。

发送

可以看出A由P1,P2,P3这3个指针描述了一个完整的发送窗口状态。

接受窗口B收到了32,33号,但B给出的确认报文字段中仍然是31,不能是32或者33。

3

B收到了31号的数据,B的窗口向前移动3个序号,同时发送给A确认,窗口仍然是20,确认号是33,B还收到了37,38,40字段,由于没有按序到达,所以暂存在接收窗口中。

最终可以看到,A发送了所有数据,P2和P3重合,由于没有收到确认,所以只能等待,如果发现超时,就重传数据。

这个过程有几点需要说明:

  • A的发送窗口并不是不变的,也不一定等于B的接收窗口,会根据网络情况适当调整。
  • 对于没有按序到达的数据,接收方会临时暂存。
  • TCP要求接收方必须能累积确认,可减小开销。就是说不用每次就确认,但也不能过分推迟,这样可能造成不必要的重传。

超时重传时间的选择

这是一个比较纠结的问题,因为每个报文的路由都有可能不同,有的快,有的慢。

自适应的解决方案,TCP会维护一个RTTs的值,叫做加权往返时间

新的RTTs = (1 - α) × 旧的RTTs + α × 新的RTT样本

RFC2988推荐的α值0.125

显然,重传超时时间RTO应略大于RTTs

RTO = RTTs + 4 × RTTd

RTTd是RTT的加权平均值

新的RTTd = (1 - β) × 旧的RTTd + β × |RTTs - 新的RTT样本|

RFC2988推荐的β值0.25

这里有个问题,如果TCP发生了重传,那么RTT就是不确定的,因为发送方,不知道是重传的ACK还是第一次传的ACK。这样就会严重影响RTO,所以,后来又规定,只要发生重传,就不更新RTTs。

但是又有新的问题,如果一段时间内报文时延突然变大,很多都超时了,这时RTO却无法更新,为了解决这个问题,后来又规定,报文每重传一次,RTO就增加一些,典型的做法是×2,实践证明,这样比较合理。

重传机制

  • 死等
  • 仅重传Timeout的包
  • 重传Timeout后所有的数据
  • 快重传(Fast Retransmit)
  • SACK方式

快重传

连续收到3个 ACK,则重传

Fast Retransmit

SACK

SACK 中携带已收到的报文序号段

SACK

TCP报文首部格式

TCP的传送的数据单元是报文段,格式如下:

TCP报文首部格式

其中有几个需要注意的字段

序号

长度是4个字节(所以范围是2的32次方-1),一个TCP连接中每个字节都是按顺序编号的,序号字段表示本报文所发送数据的第一个字节的序号。

确认号

确认号表示接收方期望收到对方下一个报文段第一个数据字节的序号。若确认号为N,则表明序号N-1的数据都已经正确收到了

URG

紧急字段(urgent),表示高优先级数据,比如中断命令,会直接插入到本报文数据段的最前面,避免所有数据处理完后才处理。与紧急指针配合使用。

ACK

确认字段(acknowlegment),仅当ACK=1时确认号才有效。

PSH

推送字段(push),优先处理报文,很少使用。

RST

复位字段(reset),当RST=1时,表示TCP连接中出现了严重错误,比如主机崩溃,必须重建连接。也可以用来拒绝以一个非法连接。

SYN

同步字段(synchronization),在建立连接时用来同步序号。

FIN

终止字段(finis),用来释放一个连接。

窗口

表示接收方允许的对方发送的数据量。

紧急指针

指出了紧急数据的长度。紧急数据后面是普通数据。

选项

SACK(选择确认),MSS(最大报文长度)等

TCP连接的建立与释放

TCP 状态机

tcpstatus

建立和释放连接

open&amp;close

有几点需要注意的

为什么是3次握手,而不是2次,4次?

  • 理论上多少次都不够,因为最后一次不能确保收到,3次基本能保证连接可靠。
  • 两次风险又太高,因为 server 收到请求就建立了链接,如果响应的 ACK client 没收到,server 会一直等待,浪费资源。

释放链接为什么是4次挥手?

TCP 是全双工协议,需要确保双方都断开链接。(解释得好牵强。。)

释放时为什么会有TIME-WAIT状态?

确保最后一个 ACK 到达 server,server 如果很久没有收到 ACK,会重发 ACK+FIN。