huahsiung

huahsiung

V2EX 第 624363 号会员,加入于 2023-04-16 14:03:40 +08:00
根据 huahsiung 的设置,主题列表被隐藏
二手交易 相关的信息,包括已关闭的交易,不会被隐藏
huahsiung 最近回复了
@lesismal 还是感谢你提供思路

原来你的思路和我的不一样,设置一个堆 Heap ,每 5s 超时,取出堆顶最后的 fd ,进行 closed 吧。这种设计只有一个 timer_fd 。
而我的是每一个 accept 后,就创建一个 timer_fd 。然后被挤爆了。

C++倒简单,使用
#include <queue>就行。

但是我是 C 语言需要自己实现 堆 Heap ,确实比较麻烦,特别是维护几十万的数据。后来去抄 apache 的堆 Heap 实现。
https://github.com/vy/libpqueue/blob/master/src/pqueue.c

堆的删除只能在对顶进行,fd 接收数据后必须删除这个堆中的数据,但是没法删除堆中。
想到的解决办法是设置 fd 标注位,fd 发现接收到数据后设置禁止 closed 的标志。


期间把把多线程架构改为了多进程,去抄了 nginx 的 master/worker 方法,发现性能确实会提升。就是通信变复杂了

其间发现,使用状态防火墙是最简单的,还不用改代码。状态防火墙会自动掐断空连接。
26 天前
回复了 csfreshman 创建的主题 C++ 如何从 c++菜鸟转型 c++高手
当然是使用 arch 滚动更新,然后使用 pacman 安装 rustc 和 cargo 。一次可以入两个神教,岂不美哉。

对于 rust ,我的观点是:“你写我推荐,我写我不写”。

哪个语言实现功能能满足需求(功能,开发效率,运行效率等等)就用那个语言。什么内存安全,老夫从来都是把指针当飞刀玩的一把梭。

> XX 机构呼吁放弃使用 C 和 C++ 了。

你看见有多少程序员忽略 warning 了,只要( CC )编译器能正常跑,这些又算什么。“呼吁”的优先等级可能还不及“warning”。最优先的当然是"error"了,其他的都可以忽略。
@lesismal

我要接的不是 bind 和 listening 的一个 listen fd 连接,而是 accept(listen_fd)出来的几十万个 client_fd 连接。我也无法区分。


另外:试了在每个 socket_fd 同时绑定一个 timer_fd ,文件描述符会膨胀 2 两倍。普通使用没有感觉,但是高并发测试下性能急剧下降。


------------------结帖-----------------

## 之前的奇淫技巧在 TCP 并发数超过 30 万+的时候指针会莫名其妙的跑飞,导致程序卡死无法退出。只能去掉这个。

之中发现百度的服务器也没有进行超时处理,运行:

`nc www.baidu.com 443`

发现一直不发送数据,连接会一直保持。



## 百度也没处理,我也不处理了,就这样吧。

另外,nginx 也可以加入
```ini
client_body_timeout 5s;
client_header_timeout 5s;
```
来进行连接超时。

使用 ab 测试,发现性能会略微下降

# nginx 未加入超时

```txt
Document Path: /
Document Length: 146 bytes

Concurrency Level: 2000
Time taken for tests: 0.950 seconds
Complete requests: 20000
Failed requests: 14144
(Connect: 0, Receive: 0, Length: 7072, Exceptions: 7072)
Non-2xx responses: 12928
Total transferred: 3736192 bytes
HTML transferred: 1887488 bytes
Requests per second: 21052.99 [#/sec] (mean)
Time per request: 94.998 [ms] (mean)
Time per request: 0.047 [ms] (mean, across all concurrent requests)
Transfer rate: 3840.72 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 40 7.8 40 60
Processing: 16 50 12.4 51 76
Waiting: 0 28 21.4 37 57
Total: 58 90 8.7 90 104

Percentage of the requests served within a certain time (ms)
50% 90
66% 93
75% 97
80% 98
90% 101
95% 103
98% 103
99% 103
100% 104 (longest request)

```

# nginx 加入 timeout 超时
```ini
client_body_timeout 5s;
client_header_timeout 5s;
```


```txt
Document Path: /
Document Length: 146 bytes

Concurrency Level: 2000
Time taken for tests: 0.971 seconds
Complete requests: 20000
Failed requests: 14464
(Connect: 0, Receive: 0, Length: 7232, Exceptions: 7232)
Non-2xx responses: 12768
Total transferred: 3689952 bytes
HTML transferred: 1864128 bytes
Requests per second: 20604.20 [#/sec] (mean)
Time per request: 97.068 [ms] (mean)
Time per request: 0.049 [ms] (mean, across all concurrent requests)
Transfer rate: 3712.33 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 41 8.7 42 71
Processing: 20 51 14.7 51 94
Waiting: 0 29 22.9 38 74
Total: 50 93 11.9 92 120

Percentage of the requests served within a certain time (ms)
50% 92
66% 99
75% 101
80% 102
90% 105
95% 109
98% 119
99% 120
100% 120 (longest request)

```

## 进行多次高并发测试,发现性能都低于。暂时没有探究原因

# 就这样了,不处理了,结帖。谢谢大家的回答
@lcdtyph 准备 x86 架构直接放弃了吧,就只能在 64 位上面运行。

准备上数据的时候把 把 pointer 的最高位(符号位) 与 0x00FFFFFF 让 pointer 变成正的。下数据使用的时候再把左移一位把“符号位”顶掉,还原负的

-----

感觉这种就像在玩飞刀一样刺激,稍不注意就“刀起头落”。唉~正常编程内存会翻 5-10 倍的,试试奇淫技巧了
@huahsiung 得到答案了,好像是编译器问题,编译器认为指针不可能为负数,帮我把“负指针”优化了。
@lcdtyph 为了省内存,我把 event[i].data.ptr 的指针当作 long long int(x64 位)用的



后来发现这个东西不会触发,不知道哪里问题。



x64 系统正常运行(除了不会触发超时)

x86 系统直接“段错误”
@Sephirothictree

select 好像不行啊,连接太多,不够用。

-----

@Nazz

SetDeadline 是 go 语言的,C/C++的库好像没用

go 语言用 go route 起几十万个连接,内存会高达 10G+的。
@lcdtyph
@choury
@henix
@BBCCBB
@roykingz

------

感谢各位回答

>TCP_DEFER_ACCEPT

我看了看 TCP_DEFER_ACCEPT 的 man,里面说(Takes an integer value (seconds), this can bound the maximum number of attempts TCP will make to complete the connection 。

就是说当重传次数超过限制之后,并且客户端依然还在回复 ack 时,到达最大超时,客户端再次回复的 syn-ack ,那么这个 defer 的连接依然会变成 ESTABLISHED 队列。必须要应用层关闭。

-----

>每个 socket 绑定一个 timer

这个方法刚才试了试,发现接到(event[i].events & EPOLLIN)后,无法区分是 timer_fd 还是 socket_fd ,就不能直接 accept(),因为可能接到 accept(timer_fd),就会错误,在程序看来都是 fd 。

-----

>记录每个 fd 上一次操作的时间戳,定时检查当前时间戳跟记录的 fd 上一次操作时间戳之差

这个我最开始就是这样的,开了一个 pthread 专门处理超时,刚开始测试一切正常。但是后来发现,TCP 连接数超过 100K 时,这个 pthread 会卡死,导致整个程序退出。然后去掉了这个超时处理的 pthread ,就一切正常。

在 800K TCP 连接左右只占了 962M 内存。每个 fd 维护一个时间轮消耗巨大,程序为每个 tcp 分配的内存只有 1k 左右,全靠 epoll 的通知和内存 pointer 撑住的。遍历上万的 fd 的话时间轮这样内存会膨胀 2~3 倍,CPU 上下文切换时间也会激增。


----

**最后的解决方法是暂时不解决,毕竟几十万左右的 TCP 连接才 4k~6k 的僵尸连接,好像也不是影响很大。**


不知道怎么把 fd 省内存的加入超时队列,我是直接把 fd CRC32 放入类似 hash 表的,但是连接过多 hash 会撞的。
54 天前
回复了 hertzry 创建的主题 问与答 学生时期的课本如何处理比较妥当
录入电子化,永久保存。100M 的空间其实就可以保存很多本书了。
@ultraqs 如果虚拟主机,模板建站,企业邮箱等等业务也算作 saas 的话,其实挺多的。
大部分企业都不会自己搭建 sendmail 之类的,一般都是用现成厂商的邮件服务。大多数中小企业官网(特别是非互联网的)也是虚拟主机,模板建站之类的,也不会自建服务器托管官网。
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2864 人在线   最高记录 6543   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 13ms · UTC 14:25 · PVG 22:25 · LAX 07:25 · JFK 10:25
Developed with CodeLauncher
♥ Do have faith in what you're doing.