当前位置: 首页 > news >正文

网站建设社会实践成果/安徽建站

网站建设社会实践成果,安徽建站,郴州网站策划,如需手机网站建设"too many open files"意味着当前进程用完了所有的文件描述符。本文简要描述如何处理这种问题。一切皆文件在Linux系统中,一切皆文件。普通文件、目录、设备以及socket都是当作文件来对待。Linux在所有这些类型的文件系统上面封装了一层虚拟文件系统(VFS)…

"too many open files"意味着当前进程用完了所有的文件描述符。本文简要描述如何处理这种问题。

一切皆文件

在Linux系统中,一切皆文件。普通文件、目录、设备以及socket都是当作文件来对待。Linux在所有这些类型的文件系统上面封装了一层虚拟文件系统(VFS),从而为上层应用提供了统一的编程接口。这里推荐一篇讲得比较好的入门级别文章:

https://ops.tips/blog/what-is-slash-proc/

下面这个图片也是来自上面这篇文章。vfs_read会将上层的read请求翻译成相应的底层文件系统的请求。

eddcc317766fa29e587286adda72cb8c.png

现在的应用程序一般都是分布式运行,相互通过网络通信。所以一般遇到“too many open files”问题都是与socket相关。本文也主要是围绕socket来描述。

文件描述符泄漏or设计缺陷?

一旦发生"too many open files",一般有两种可能,要么是代码有BUG,导致socket泄漏,要么是有设计缺陷。

如果遇到突发流量,导致socket激增,但是当流量减弱或消失后,socket数量能逐渐回归到正常。那就说明没有socket泄漏。这时往往是设计问题,由于没有相应的熔断限流措施,以及没有设置合理的最大文件描述符数。

如果当流量减弱后,socket数量还是居高不下,那就说明有泄漏,就需要排查代码问题。

定位工具

一般来说,定位这类问题,有三种常用的方法或者工具。

/proc//fd

第一种方式是直接查看"/proc//fd"这个目录中的文件。其中是要查看的进程的ID,例如下面就是进程29716打开的所有文件,

d1cbae2ec86b85ff770a5fea020927bd.png

用下列命令就可以快速统计进程打开的文件描述符的总数(注意:要刨去第一行:)),

ls -lrt /proc/29716/fd | wc -l

如果是进程在代码中查看自己占用的文件描述符时,则可以直接访问/proc/self/fd这个目录,因为/proc/self其实就是指向/proc/的一个链接。Golang代码如下,

fds, err := ioutil.ReadDir("/proc/self/fd")

lsof

使用"lsof -p "也可以查询某个进程占用的所有文件描述符。例如下面就是查询进程29716打开的所有文件描述符。lsof显示的信息比/proc//fd更全一点,而且条目稍多,因为它将进程所在的目录以及加载的动态库也算在内。但是最终系统报"too many open files"时,是以/proc//fd中所包含的条目为准。

5b691795a9f5b5bf548443b7a778eb7b.png

netstat

netstat可以很方便的查看本机的网络连接情况。例如下面的截图就是执行如下命令的输出。如果要查看某个进程的连接信息,可以根据pid过滤。

netstat -nap | grep tcp

13d7e4087ac8d815a8bdddd48c040723.png

TCP状态机
分析socket问题,一定要会看TCP状态机,要清楚各个状态分别代表什么含义,以及相互之间如何转化。下图来自google搜索。

45093f0a8ecdf4d751f858068a5ba4d2.png

首先,一定要明白TCP是双工的,当一方关闭连接,只表示它没有数据要发送了,但是它还可以接受数据。只有双方都关闭了连接,才算最终关闭了连接。

在上面众多的状态中,CLOSE_WAIT这个状态需要重点关注。其含义是对方已经关闭了TCP连接,但自己这方还没有关闭连接。如果不是故意这么设计或实现,往往意味着代码中有BUG,没有及时关闭连接。如果由于处于CLOSE_WAIT状态的socket过多,导致“too many open files”,那八成就是代码中在需要调用close关闭连接的地方遗漏了。

另外,TIME_WAIT是一种正常的状态。当双方都关闭了连接,主动关闭的一方最后会进入TIME_WAIT状态,等待2MSL的时间之后,就会自动变成CLOSED状态。其目的是确保对方能收到最后一个ACK包,以及等待网络中延迟的各种包消失。

如果看到很多SYNC_WAIT,那说明对方网络不通,和对方的连接无法建立。

getrlimit & setrlimit

如果需要,可以设置更大的文件描述符数量。可以通过ulimit命令,或者系统调用setrlimit来设置。ulimit是一个shell命令,它设置shell以及通过shell启动的进程的资源限制,它最后也是调用setrlimit。这里推荐一篇很简单实用的文章:

https://www.robustperception.io/dealing-with-too-many-open-files

获取或设置当前进程的资源限制,可以使用系统调用getrlimit和setrlimit,

#include #include int getrlimit(int resource, struct rlimit *rlim);int setrlimit(int resource, const struct rlimit *rlim);

Golang中对应的系统调用定义在syscall包中,不过从go1.4之后,应用使用golang.org/x/sys中的包。

func Getrlimit(resource int, rlim *Rlimit) (err error)func Setrlimit(resource int, rlim *Rlimit) (err error)

这里一定要分清soft limit和hard limit。首先, soft limit肯定小于或等于hard limit。对于某个进程来说,起作用的是soft limit。如果不是特权用户,只能调整soft limit,最大可以调成与hard limit一样大。对于特权用户,可以同时修改soft limti和hard limit,但同样soft limit不能超过hard limit。例如Golang中,Getrlimit返回的结构体中,Cur对应的是soft limit,而Max则是hard limit。

type Rlimit struct {    Cur uint64    Max uint64}

一般来说,在linux系统中,soft limit和hard limit默认分别是1024和4096。

etcd的做法

etcd有一个goroutine来监控文件描述符的使用情况,代码如下,

// https://github.com/etcd-io/etcd/blob/master/etcdserver/metrics.go#L201func monitorFileDescriptor(lg *zap.Logger, done   ticker := time.NewTicker(10 * time.Minute)  defer ticker.Stop()  for {    used, err := runtime.FDUsage()    if err != nil {      lg.Warn("failed to get file descriptor usage", zap.Error(err))      return    }    fdUsed.Set(float64(used))    limit, err := runtime.FDLimit()    if err != nil {      lg.Warn("failed to get file descriptor limit", zap.Error(err))      return    }    fdLimit.Set(float64(limit))    if used >= limit/5*4 {      lg.Warn("80% of file descriptors are used", zap.Uint64("used", used), zap.Uint64("limit", limit))    }    select {    case C:    case done:      return    }  }}

从上面的代码中,不难看出,通过两个metrics (fdUsed和fdLimit) 与普罗米修斯(prometheus)做了集成。

上面代码中的,FDLimit和FDUsage的实现如下。其中FDUsage就是通过目录"/proc/self/fd"来统计当前进程打开的文件描述符总数的。而FDLimit是利用了系统调用Getrlimit。

func FDLimit() (uint64, error) {  var rlimit syscall.Rlimit  if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit); err != nil {    return 0, err  }  return rlimit.Cur, nil}func FDUsage() (uint64, error) {  return countFiles("/proc/self/fd")}

正确使用Golang中Transport

在Golang中,客户端通过http访问服务器时,会使用到http.Transport。这里要注意一点,Transport维护了一个连接池。所以在实际使用中,不要为每一个HTTP请求创建一个新的Transport。正确的做法是只创建一个http.Client和http.Transport,以后每个http请求都使用同一个client。具体参考下面这个issue,

https://github.com/golang/go/issues/24719

--END--

相关文章

Prometheus + Grafana构建云时代的monitoring解决方案

http://www.lbrq.cn/news/2343817.html

相关文章:

  • 富顺做网站/百度广告官网
  • 网站开发 动易/安卓优化
  • 长春网络建站/seo外链资源
  • 网站图怎么做会高清图片/百度小说排行榜2020
  • 简繁英3合1企业网站生成管理系统/怎样在百度上做广告
  • 广州做网站 timhi/广告安装接单app
  • 黔东网站建设/十大洗脑广告
  • 桂平逗乐游戏招聘网站开发/拉新app推广接单平台
  • 网站建设摘要/优化网站排名
  • 网站建设与seo论文/丁的老头seo博客
  • 学做网站的视频/镇江网站定制
  • 庆阳定制网站/淘宝补流量平台
  • 企业网站优化外包/成都网站推广哪家专业
  • 多后缀域名查询网站/外贸互联网推广的
  • 嘉兴做网站建设的公司/网站自动秒收录工具
  • 网站设计公司佛山/百度热搜词排行榜
  • wordpress翻译教程/当阳seo外包
  • 呼叫中心网站建设/如何注册网址
  • 政府网站谁来做/四川二级站seo整站优化排名
  • 创新网站设计/全国培训机构排名前十
  • 网站建设行业怎么样/seo优化中商品权重主要由什么决定
  • 南宁推广软件/武汉seo优化服务
  • 怎么做网购网站/合肥seo优化排名公司
  • 国内做视频的网站有哪些/外链发布软件
  • 帝国网站数据库配置文件/2345网址中国最好
  • 云南商城网站建设/关键词你们懂的
  • 沈阳电子商务网站建设/百度seo推广
  • 新疆建设监理协会网站/百度灰色关键词技术
  • 搭建php网站环境/地推的方法和技巧
  • 做跨境网站注意事项/搜索引擎优化的具体操作
  • ESP32S3+VSCode+PlatformIO+Arduino+Freertos开发入门指南:基于Arduino框架的应用开发全流程
  • 【BUG处理】构建APK时遇到错误:‘flutter‘ 命令未被识别。这通常表示您的系统中未安装Flutter SDK或环境变量配置不正确。
  • 【深度学习优化算法】06:动量法
  • 【PTA数据结构 | C语言版】前序遍历二叉树
  • 安装Keycloak并启动服务(macOS)
  • C# TCP粘包与拆包深度了解