0%

在项目开发过程中,最好是能估计出自己开发的功能要使用多大的redis内存

使用redis自带的方法

debug object key

1
2
3
4
127.0.0.1:6006> get testkey
"this is a test"
127.0.0.1:6006> debug object testkey
Value at:0x7f4f19e2b500 refcount:1 encoding:embstr serializedlength:15 lru:14327341 lru_seconds_idle:6
  • Value at: 内存地址
  • refcount: 引用次数
  • encoding: 编码类型
  • serializedlength: 序列化后的长度(注意这里的长度是序列化后的长度,保存为rdb文件时使用了该算法,不是真正存贮在内存的大小,不过可以用于比较)memory usage1
    2

127.0.0.1:6006> memory usage queuesSet
(integer) 1489075554

返回字节数

借助工具

借助redis rdb tools工具,需要下载rdbtools,pip install rdbtools

1
2
3
4
banfushen@banfushen:~$ redis-memory-for-key -p 6006 testkey
Key testkey
Bytes 72
Type string

使用脚本

1
2
3
4
5
6
7
import redis

h = 'localhost'
p = 6006

rd = redis.Redis(host=h, port=p, decode_responses=True)
print(rd.type('testkey'), rd.strlen('testkey'))
1
2
banfushen@banfushen:~/gitlab/dbsync/test$ python redis_size.py 
(u'string', 14)

开发这么久,第一次这种问题,记录一下。
在某天开发中,开发机的cpu忽然飙升,一直降不下来,刚开始没注意,一直删除cpu占用高的进程,一直无效,仔细看。top显示Steal高。
经过查询是因为宿主机出了问题,详细说明看这里。
然后联系了运维,更换了宿主机,解决。

背景

就像上一篇所说,我使用了docker-componse启动了redis cluster集群。经过了一天的测试,本来测试已经完毕了,但是今天修改了点代码,再次测试的时候发现redis cluster起不来了。报错CLUSTERDOWN Hash slot not served。从这个错误提示,可以看出是slot分配原因造成的。上网找,真的蛋疼,你复制我,我复制你,最后还是得自己解决。

查看详细

1
2
3
4
5
6
7
8
9
10
11
12
banfushen@banfushen:~/redis-cluster$ redis-cli -p 16379
127.0.0.1:16379>
127.0.0.1:16379>
127.0.0.1:16379> CLUSTER info
cluster_state:fail
cluster_slots_assigned:0
cluster_slots_ok:0
cluster_slots_pfail:0
cluster_slots_fail:0
...
127.0.0.1:16379> CLUSTER SLOTS
Empty slot

直接修复

猜测就是slot分配的问题,进入具体container,重新分配slot

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
banfushen@banfushen:~/redis-cluster$ docker exec -it redis-node-0 /bin/bash
root@a77b8222eba2:/#
## 先查看命令
root@a77b8222eba2:/# redis-cli --cluster help
Cluster Manager Commands:
create host1:port1 ... hostN:portN
--cluster-replicas <arg>
check host:port
--cluster-search-multiple-owners
info host:port
fix host:port
--cluster-search-multiple-owners
--cluster-fix-with-unreachable-masters
reshard host:port
--cluster-from <arg>
--cluster-to <arg>
--cluster-slots <arg>
--cluster-yes
--cluster-timeout <arg>
--cluster-pipeline <arg>
--cluster-replace
rebalance host:port
--cluster-weight <node1=w1...nodeN=wN>
--cluster-use-empty-masters
--cluster-timeout <arg>
--cluster-simulate
--cluster-pipeline <arg>
--cluster-threshold <arg>
--cluster-replace
add-node new_host:new_port existing_host:existing_port
--cluster-slave
--cluster-master-id <arg>
del-node host:port node_id
call host:port command arg arg .. arg
--cluster-only-masters
--cluster-only-replicas
set-timeout host:port milliseconds
import host:port
--cluster-from <arg>
--cluster-from-user <arg>
--cluster-from-pass <arg>
--cluster-from-askpass
--cluster-copy
--cluster-replace
backup host:port backup_directory
help

For check, fix, reshard, del-node, set-timeout you can specify the host and port of any working node in the cluster.

Cluster Manager Options:
--cluster-yes Automatic yes to cluster commands prompts

## 直接修复
root@a77b8222eba2:/# redis-cli --cluster fix --cluster-search-multiple-owners 127.0.0.1:6379
...
>>> Covering slot 694 with 192.168.88.3:6379
>>> Check for multiple slot owners...
[OK] No multiple owners found.
root@f3f2043dba55:/#
root@f3f2043dba55:/#
root@f3f2043dba55:/#
root@f3f2043dba55:/# redis-cli -p 6379
127.0.0.1:6379> cluster info
cluster_state:ok
cluster_slots_assigned:16384
cluster_slots_ok:16384
cluster_slots_pfail:0
cluster_slots_fail:0
cluster_known_nodes:6
cluster_size:6
cluster_current_epoch:33
cluster_my_epoch:30
cluster_stats_messages_ping_sent:489
cluster_stats_messages_pong_sent:523
cluster_stats_messages_meet_sent:6
cluster_stats_messages_sent:1018
cluster_stats_messages_ping_received:523
cluster_stats_messages_pong_received:495
cluster_stats_messages_received:1018
127.0.0.1:6379> exit
root@f3f2043dba55:/# exit

背景

项目用到一个redis库,对于里面的集群相关功能要自己测试(就像《代码简洁之道》中说的,使用第三方库需要自己有测试用例,这样即使第三方库更新了,直接用原来的测试用例,也知道是否能兼容)。所以需要自己本地搭建redis集群测试。

搭建是使用docker搭建的,一下需要启动很多个container,所以使用docker-compose作为容器编排我的环境已经有了,没有的自己下载

直接上redis-cluster模式

redis集群有三种模式:master+slave(主从)、sentinel(哨兵)、cluster(集群)
我实际项目用的cluster模式,所以这里直接使用cluster模式。这个docker-compose.yml参考至docker 部署 redis 的三种集群模式,里面还有一些关于redis集群的说明,docker-compose.yml我亲自使用,没问题。

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
## docker-compose.yml
version: '2'
services:
redis-node-0:
user: root
container_name: redis-node-0
image: docker.io/bitnami/redis-cluster:6.2
ports:
- 16379:6379
volumes:
- ./redis_data-0:/bitnami/redis/data
environment:
- 'ALLOW_EMPTY_PASSWORD=yes'
- 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'
networks:
redis-cluster-network:
ipv4_address: 192.168.88.2

redis-node-1:
user: root
container_name: redis-node-1
image: docker.io/bitnami/redis-cluster:6.2
ports:
- 16380:6379
volumes:
- ./redis_data-1:/bitnami/redis/data
environment:
- 'ALLOW_EMPTY_PASSWORD=yes'
- 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'
networks:
redis-cluster-network:
ipv4_address: 192.168.88.3

redis-node-2:
user: root
container_name: redis-node-2
image: docker.io/bitnami/redis-cluster:6.2
ports:
- 16381:6379
volumes:
- ./redis_data-2:/bitnami/redis/data
environment:
- 'ALLOW_EMPTY_PASSWORD=yes'
- 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'
networks:
redis-cluster-network:
ipv4_address: 192.168.88.4

redis-node-3:
user: root
container_name: redis-node-3
image: docker.io/bitnami/redis-cluster:6.2
ports:
- 16382:6379
volumes:
- ./redis_data-3:/bitnami/redis/data
environment:
- 'ALLOW_EMPTY_PASSWORD=yes'
- 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'
networks:
redis-cluster-network:
ipv4_address: 192.168.88.5

redis-node-4:
user: root
container_name: redis-node-4
image: docker.io/bitnami/redis-cluster:6.2
ports:
- 16383:6379
volumes:
- ./redis_data-4:/bitnami/redis/data
environment:
- 'ALLOW_EMPTY_PASSWORD=yes'
- 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'
networks:
redis-cluster-network:
ipv4_address: 192.168.88.6

redis-node-5:
user: root
container_name: redis-node-5
image: docker.io/bitnami/redis-cluster:6.2
ports:
- 16384:6379
volumes:
- ./redis_data-5:/bitnami/redis/data
depends_on:
- redis-node-0
- redis-node-1
- redis-node-2
- redis-node-3
- redis-node-4
environment:
- 'ALLOW_EMPTY_PASSWORD=yes'
- 'REDISCLI_AUTH=bfsbfs'
- 'REDIS_CLUSTER_REPLICAS=1'
- 'REDIS_NODES=redis-node-0 redis-node-1 redis-node-2 redis-node-3 redis-node-4 redis-node-5'
- 'REDIS_CLUSTER_CREATOR=yes'
networks:
redis-cluster-network:
ipv4_address: 192.168.88.7

networks:
redis-cluster-network:
driver: bridge
ipam:
config:
- subnet: 192.168.88.0/24

直接docker-compose up -d

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
## 在dockers-compose.yml目录
docker-compose up -d

Creating network "rediscluster_redis-cluster-network" with driver "bridge"
Pulling redis-node-4 (docker.io/bitnami/redis-cluster:6.2)...
6.2: Pulling from bitnami/redis-cluster
1d7019cad1df: Pull complete
0c20d9bbd5c0: Pull complete
7434cc9f2f61: Pull complete
01dd376516ef: Pull complete
a10fc7cec580: Pull complete
2e7c2cbaa852: Pull complete
eef01af132bf: Pull complete
234dbecfe19a: Pull complete
Digest: sha256:57e9093dfaa412c691592e7e2ca6402a6f7d76b10cff04669fca4a82365f1874
Status: Downloaded newer image for bitnami/redis-cluster:6.2
WARNING: Connection pool is full, discarding connection: localhost
WARNING: Connection pool is full, discarding connection: localhost
WARNING: Connection pool is full, discarding connection: localhost
Creating redis-node-2
Creating redis-node-4
Creating redis-node-0
WARNING: Connection pool is full, discarding connection: localhost
WARNING: Connection pool is full, discarding connection: localhost
Creating redis-node-3
Creating redis-node-1
WARNING: Connection pool is full, discarding connection: localhost
WARNING: Connection pool is full, discarding connection: localhost
WARNING: Connection pool is full, discarding connection: localhost
WARNING: Connection pool is full, discarding connection: localhost
WARNING: Connection pool is full, discarding connection: localhost
WARNING: Connection pool is full, discarding connection: localhost
WARNING: Connection pool is full, discarding connection: localhost
WARNING: Connection pool is full, discarding connection: localhost
Creating redis-node-5

测试完毕,停止redis

1
2
3
## 在dockers-compose.yml目录
docker-compose stop
docker-compose rm

背景

开发机上装了minikube,起了一个docker镜像当minikube的宿主机,在启动了一定量的deployment A之后,deployment A就全挂了(启动1~2个deployment A,没有问题,启动到第三个,就全挂)。然后宿主机卡爆。

查询pod挂的原因

1
2
3
4
5
6
7
8
9
kubectl describe pod 

...
Exit Code: 137
Started: Wed, 29 Sep 2021 16:02:30 +0800
Finished: Wed, 29 Sep 2021 16:04:19 +0800
Ready: False
Restart Count: 12
...

看到了其中镜像挂了的返回值是137,此状态码一般是因为 pod 中容器内存达到了它的资源限制(resources.limits),一般是内存溢出(OOM),CPU达到限制只需要不分时间片给程序就可以。因为限制资源是通过 linux 的 cgroup 实现的,所以 cgroup 会将此容器强制杀掉,类似于 kill -9。
但是通过top查看发现cpu和内存都没满,但是内存交换满了(KiB Swap),感觉是因为宿主机没资源了,所以干掉pod中的资源,接着往下查,寻找更多node的信息。

因为minikube是起在docker中的,所以查看一下docker状态

1
2
3
4
5
6
7
docker stats

94ec0f757f48 banfushen6_elasticsearch_1 1.24% 1.653GiB / 4.657GiB 35.49% 9.15GB / 6.79GB 85.3MB / 38.6GB 205
a57d56927433 banfushen6_dynamodb_1 17.73% 329.7MiB / 31.42GiB 1.02% 223MB / 188MB 17MB / 12.3kB 86
6aa3384e7433 banfushen6_mongooseim_1 0.02% 287.6MiB / 31.42GiB 0.89% 4.22MB / 0B 19.3MB / 1.03MB 27
6f8203c6c8bd banfushen6_rabbitmq_1 0.11% 98.38MiB / 31.42GiB 0.31% 4.22MB / 0B 19.9MB / 3.94MB 307
722f40c6405f minikube 205.57% 7.398GiB / 7.812GiB 94.69% 441MB / 8.04MB 4.08MB / 48.1kB 2218

这下,找到了pod失败的原因。接下来查找宿主机卡住的原因。

查看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
kubectl describe node minikube
Name: minikube
Roles: master
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=minikube
kubernetes.io/os=linux
minikube.k8s.io/commit=2c82918e2347188e21c4e44c8056fc80408bce10
minikube.k8s.io/name=minikube
minikube.k8s.io/updated_at=2021_07_20T17_14_34_0700
minikube.k8s.io/version=v1.14.2
node-role.kubernetes.io/master=
Annotations: kubeadm.alpha.kubernetes.io/cri-socket: /var/run/dockershim.sock
node.alpha.kubernetes.io/ttl: 0
volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp: Tue, 20 Jul 2021 17:14:27 +0800
Taints: <none>
Unschedulable: false
Conditions:
Type Status LastHeartbeatTime LastTransitionTime Reason Message
---- ------ ----------------- ------------------ ------ -------
MemoryPressure False Wed, 29 Sep 2021 17:02:14 +0800 Wed, 29 Sep 2021 16:37:39 +0800 KubeletHasSufficientMemory kubelet has sufficient memory available
DiskPressure False Wed, 29 Sep 2021 17:02:14 +0800 Wed, 29 Sep 2021 16:37:39 +0800 KubeletHasNoDiskPressure kubelet has no disk pressure
PIDPressure False Wed, 29 Sep 2021 17:02:14 +0800 Wed, 29 Sep 2021 16:37:39 +0800 KubeletHasSufficientPID kubelet has sufficient PID available
Ready True Wed, 29 Sep 2021 17:02:14 +0800 Wed, 29 Sep 2021 16:57:04 +0800 KubeletReady kubelet is posting ready status

看到了这句话kubelet has no disk pressure,在结合之前top的交换内存满了,判定磁盘的问题。通过公司的monitor查看到机器的磁盘io使用率已满。
在这里插入图片描述

找出导致io爆炸的容器

我先用了pidstat -d 1查看哪个进程对io的占用最高,但是缺没找到任何相关信息,然后直接在宿主机查看内核日志

1
2
3
cat /var/log/messages | ag killed

Sep 29 17:50:31 bfs kernel: [5618442.047786] Task in /docker/722f40c6405f6933ac2722e40a40fef4c52e36b2ba0e44bdd1a8aba0027ca313/kubepods/besteffort/pod4909103c-cdc2-432e-92aa-2e06c2c7d1e3/9d62c1f82041c40d691498b2ded86caa663404489f7c3a62ad37c72eb2470911 killed as a result of limit of /docker/722f40c6405f6933ac2722e40a40fef4c52e36b2ba0e44bdd1a8aba0027ca313

可以看到,docker被内核干掉了,拿到docker的id前缀,去查找看是什么容器造成的。

1
2
docker@minikube:~$ docker ps | grep  e5bdaaef
e5bdaaefff4a 7c797432e61c "/usr/local/bin/dock…" 11 minutes ago Up 11 minutes k8s_elasticsearch

发现,原来是pod中启动了es,多个es导致io炸裂,最后修改pod资源,不启动es,解决问题

本是小辣鸡。以前也只是写业务代码,全靠领导给机会让我自己负责一个服务器的编写,部署,上线需要的资源评估。记录第一次做上线资源评估的过程。

项目背景是,搭在云服务商上的集群,集群管理是kubernetes。首次内测目标5000个用户。

主要如下

1.服务器需要多少内存
2.服务器需要多少cpu
3.了解购买的云服务参数
4.修改kubernetes部署文件

首先需要做压测,我写的服务器是用golang写的用于聊天服务器,所以在世界聊天的时候,压力就会非常大。压力也是要测试这里,看看需要消耗多少性能。

服务器需要多少内存

我使用了golang的profile进行分析,登录了5000玩家后,在profile中,查看到内存情况总共消耗171000000字节左右。计算出一个玩家大约使用32KB的内存。服务器本身启动不占多少内存,最后评估需要256m的内存。

服务器需要多少cpu

在压测的时候,已经看了cpu的profile,看上去一切正常。剩下就是发消息。我启动服务器的机器是16核,2.2GHz的服务器。在每秒200人同时发消息到世界频道,5000人接收的情况下。使用top命令查看最高的时候,跑了586%的cpu,按6个计算,就是6*2200mhz = 13200mhz。也就是说在最极端的情况下,全部人都不玩游戏,只在大厅聊天,每秒200个人发,按照计算最多需要13200mhz的cpu。

了解购买的云服务参数

集群中总共有8台机器,每台8G内存,4个cpu,每个cpu是3.4Ghz约等于3400mhz,4个cpu大约13600mhz。

修改kubernetes部署文件

因为要充分利用机器性能,所以不能够只部署一个pod,我的服务器之部署一个pod的话,会直接压干一台云服务器的cpu,导致这台云服务器只剩下400mhz的cpu,可能无法起别的pod,上面的内存也将被浪费掉。所以必须起多个pod。最终决定用以下配置,每个pod请求1000M内存,1整个核心的cpu,最大只给2000M内存和两个核心的cpu。

1
2
3
4
5
6
requests:
memory: 1000Mi
cpu: 1000m
limits:
memory: 2000Mi
cpu: 2000m

这样,一台云机器最少还有6G内存,和3个cpu可以分配给别的pod,不会造成资源浪费。另外,等到真正上线的时候,如果人太多了,资源不够用也是不怕的。kubernetes还有自动扩容。

今早收到了Prometheus的报警,4% of Kubernetes nodes are not ready。

直接查看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
banfushen@pro:~/helm-chart/prometheus-netease/templates$ kubectl describe nodes ip-xx-x-xxx-xxx.ap-northeast-1.compute.internal
Name: ip-xx-x-xxx-xxx.ap-northeast-1.compute.internal
Roles: node
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/instance-type=c5.xlarge
beta.kubernetes.io/os=linux
failure-domain.beta.kubernetes.io/region=ap-northeast-1
failure-domain.beta.kubernetes.io/zone=ap-northeast-1c
kubernetes.io/hostname=ip-xx-x-xxx-xxx.ap-northeast-1.compute.internal
kubernetes.io/role=node
node-role.kubernetes.io/node=
Annotations: node.alpha.kubernetes.io/ttl: 0
volumes.kubernetes.io/controller-managed-attach-detach: true
CreationTimestamp: Sat, 24 Jul 2021 03:05:08 +0800
Taints: <none>
Unschedulable: false
Conditions:
Type Status LastHeartbeatTime LastTransitionTime Reason Message
---- ------ ----------------- ------------------ ------ -------
OutOfDisk False Sat, 24 Jul 2021 18:00:31 +0800 Sat, 24 Jul 2021 03:05:08 +0800 KubeletHasSufficientDisk kubelet has sufficient disk space available
MemoryPressure False Sat, 24 Jul 2021 18:00:31 +0800 Sat, 24 Jul 2021 03:05:08 +0800 KubeletHasSufficientMemory kubelet has sufficient memory available
DiskPressure False Sat, 24 Jul 2021 18:00:31 +0800 Sat, 24 Jul 2021 03:05:08 +0800 KubeletHasNoDiskPressure kubelet has no disk pressure
PIDPressure False Sat, 24 Jul 2021 18:00:31 +0800 Sat, 24 Jul 2021 03:05:08 +0800 KubeletHasSufficientPID kubelet has sufficient PID available
Ready True Sat, 24 Jul 2021 18:00:31 +0800 Sat, 24 Jul 2021 03:05:28 +0800 KubeletReady kubelet is posting ready status

项目上redis cluster数据产生了倾斜,项目是有3个节点,但第一个节点用了80%的内存,第二第三个节点基本没存数据。

redis cluster存贮规律

redis 集群有16384个槽,会先对要存贮的key进行hash,将得到的结果放到对应的槽。一般会对整个key进行hash,如果key中含有{},会对{}中的字符串进行哈希。

先查看集群中是否是因为key的原因造成倾斜

1
2
redis-cli -h xxx.xxx.xxx.xxx -p xxx -c
keys *{*}*

查看之后发现,并不是因为{}导致key全部塞到第一个节点,说明应该不是key的原因

查找集群中的大key

1
2
redis-cli -h xxx.xxx.xxx.xxx -p xxx -c --bigkeys
redis-memory-for-key -s xxx.xxx.xxx.xxx -p xxx keyname

这里有一点需要注意,bigkeys命令会再各个节点中遍历,一个节点一个节点的插,所以要多执行几遍。最后发现有一个list里面有3W多个数据,查看大小,就是这个原因导致的,最后再查询代码,发现是业务代码问题,解决即可。
redis-memory-for-key也可能没连接到指定节点,需要多执行几次。

服务器最近压测的时候发现了问题。发现是往channel写数据,但是channel满了,导致服务器部分功能阻塞。golang的channel读或写是会造成阻塞的,但是可以用select的多路复用解决这个问题。

不阻塞读channel(也可以加上超时)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func readChan(c chan int) (int, error) {
select {
case num := <-c:
return num, nil
default:
return 0, errors.New("chan do not have data")
}
}

// 加上超时时间
func readChanWithTimeout(c chan int) (int, error) {
timeout := time.NewTimer(time.Microsecond * 100)

select {
case num := <-c:
return num , nil
case <-timeout.C:
return 0, errors.New("read chan time out")
}
}

非阻塞写入channel(也可以加上超时)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
func writeChan(num int, c chan int) error {
select {
case ch <- num:
return nil
default:
return errors.New("chan is full")
}
}

// 加上超时时间
func writeChanWithTimeout(num int, c chan int) error {
timeout := time.NewTimer(time.Microsecond * 100)

select {
case c <- num:
return nil
case <-timeout.C:
return errors.New("write chan time out")
}
}

最近更换了服务器的消息队列,客户端反馈说服务器有时候会多发消息下去,十分纳闷,只改了服务器的消息队列,但是服务器像客户端发消息的代码一行没改,日志也只是发一条消息下去,但是因为改了消息队列,最后使用linux抓包看看,以证清白。

tcpdump输出demo如下(这不是调试时的数据,只是demo)。这里我指定查看8060端口。

1
2
3
4
5
root@mdev-2:/home/banfushen/webclient# tcpdump port 8060
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
17:41:07.061086 IP 10.xxx.xxx.xxx.51321 > 11.xxx.xxx.xxx.8060: Flags [.], seq 2312385062:2312385063, ack 2244282406, win 1021, length 1
17:41:07.061177 IP 11.xxx.xxx.xxx.8060 > 10.xxx.xxx.xxx.51321: Flags [.], ack 1, win 101, options [nop,nop,sack 1 {0:1}], length 0

抓包之后,发现的确只发下去一条,然后去抓客户端,在客户端打断点调试,最后发现是客户端自己的确收到一条,但是别的逻辑导致事件重复触发。最后证明清白。

tcpdump还有一些别的命令做一下记录:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 监听指定网卡
tcpdump -i en0

# 监听本机与192.xxx.xxx.xx之间的通信包,出\入都会监听
tcpdump host 192.xxx.xxx.xx

# 监听192.xxx.xxx.xx来源的通信
tcpdump src host 192.xxx.xxx.xx

# 监听192.xxx.xxx.xx为目标的通信
tcpdump dst host 192.xxx.xxx.xx

# 监听3000端口
tcpdump port 3000

tcpdump非常强大,还有一些更多的功能用到的时候再查询。