原文链接: 这个 TCP 问题你得懂:Cannot assign requested address
微信群里一阵动乱,响声震天。
我心想,尽管是周五,并且到了上班点,但也不至于这么兴奋吧。
关上微信一看,心凉半截,全是报零碎 403
谬误的音讯。别说上班了,怕是老板会让我永远上班吧。
别慌,在长期的团队合作训练中,我明确了一个情理:稳住咱们能赢。
冷静下来之后,我仔细分析了一下问题的起因。
403
阐明权限有余,也就是说咱们的子系统到鉴权核心拉取权限失败了。间接登录到子系统服务器,手动执行拉取权限程序,确实是拉不到。
我的揣测没有问题,难道网络不通了?telnet
指标端口试试,而后 Linux 给我返回了这个错误信息:
Cannot assign requested address
起因
产生这个谬误的起因是因为 Linux 调配的客户端连贯端口用尽,无奈建设 socket 连贯导致的。
咱们都晓得,建设一个连贯须要四个局部:指标 IP,指标端口,客户端 IP 和客户端端口。其中前三项是不变的,只有客户端端口一直变动。
那么在大量频繁建设连贯时,而端口又不是立刻开释,默认是 60s,就会呈现客户端端口不够用的状况。
这就是这个问题的实质。
接下来应用两个命令来验证一下:
查看连接数:
# netstat -ae | wc -l
# netstat -ae | grep TIME_WAIT | wc -l
查看可用端口范畴:
# sysctl -a | grep port_range
net.ipv4.ip_local_port_range = 50000 65000
后果就是连接数是远大于可用端口数的。
解决
怎么解决呢?有两个计划:
- 调低 TIME_WAIT 工夫
- 调高可用端口范畴
调低 TIME_WAIT 工夫
编辑内核文件 /etc/sysctl.conf
,减少以下内容:
// 示意开启 SYN Cookies。当呈现 SYN 期待队列溢出时,启用 cookies 来解决,// 可防备大量 SYN 攻打,默认为 0,示意敞开;net.ipv4.tcp_syncookies = 1
// 示意开启重用。容许将 TIME-WAIT sockets 从新用于新的 TCP 连贯,默认为 0,示意敞开;net.ipv4.tcp_tw_reuse = 1
// 示意开启 TCP 连贯中 TIME-WAIT sockets 的疾速回收,默认为 0,示意敞开。net.ipv4.tcp_tw_recycle = 1
// 批改系默认的 TIMEOUT 工夫,默认为 60s
net.ipv4.tcp_fin_timeout = 30
调高可用端口范畴
编辑内核文件 /etc/sysctl.conf
,减少以下内容:
// 示意用于向外连贯的端口范畴。设置为 1024 到 65535。net.ipv4.ip_local_port_range = 1024 65535
最初,执行 sysctl -p
使参数失效。
复盘
我通过减少可用端口范畴,顺利将问题解决,看来能够失常上班了。
然而还没完,为什么会忽然有这么多连贯呢?通过剖析日志发现,过来一段时间,我的一个共事疯狂申请零碎接口,应该就是这个操作引起的,问了一下原来是在爬数据。好家伙间接来硬的,找我提供一个 API 不香吗?
不过这也反馈了咱们的零碎也太过软弱,一个小爬虫就给搞挂了。剖析了线上代码,感觉有三个中央应该优化:
- 每次申请鉴权核心不应该都建设新的连贯,而是应该复用之前的连贯,比方单例模式;
- 权限相对来说是变动不频繁的,子系统应该建设本地缓存,而不是每次实时申请;
- 不止要对
POST
接口设置频率限度,GET
接口也应该限度。
剩下的事就是优化代码了,不过,先开心的过个周末再说。
文章中的脑图和源码都上传到了 GitHub,有须要的同学可自行下载。
地址: https://github.com/yongxinz/t…
关注公众号 AlwaysBeta,回复「goebook」支付 Go 编程经典书籍。
Go 专栏文章列表:
- Go 专栏|开发环境搭建以及开发工具 VS Code 配置
- Go 专栏|变量和常量的申明与赋值
- Go 专栏|根底数据类型:整数、浮点数、复数、布尔值和字符串
- Go 专栏|复合数据类型:数组和切片 slice
- Go 专栏|复合数据类型:字典 map 和 构造体 struct
- Go 专栏|流程管制,一网打尽
- Go 专栏|函数那些事
- Go 专栏|错误处理:defer,panic 和 recover
- Go 专栏|说说办法
- Go 专栏|接口 interface