-
Notifications
You must be signed in to change notification settings - Fork 2.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pipeline支持 #908
Comments
用golang标准库server则能正常返回并且连接没有被关闭: package main
import (
"net/http"
"sync/atomic"
"time"
)
var (
cnt = int64(0)
)
type HttpHandler struct{}
func (h *HttpHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
ret := ""
if atomic.AddInt64(&cnt, 1)%2 == 1 {
ret = "aaaaa"
time.Sleep(time.Second)
} else {
ret = "bbbbb"
}
w.Header().Add("Date", time.Now().Format(time.RFC1123)) //"Mon, 02 Jan 2006 15:04:05 MST"
w.Header().Add("Content-Type", "text/plain; charset=UTF-8")
w.Write([]byte(ret))
}
func main() {
server := http.Server{
Addr: "localhost:9000",
Handler: &HttpHandler{},
}
server.ListenAndServe()
} output: root@k8s:~/workflow/benchmark# go run ./client.go
---------------------
write:
GET / HTTP/1.1
Host: localhost:9000
GET / HTTP/1.1
Host: localhost:9000
---------------------
read:
HTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Date: Sun, 15 May 2022 06:39:04 UTC
Content-Length: 5
aaaaaHTTP/1.1 200 OK
Content-Type: text/plain; charset=UTF-8
Date: Sun, 15 May 2022 06:39:04 UTC
Content-Length: 5
bbbbb client连接挂起、并未被关闭 |
pipeline应该算是http1.1 server的一项标准功能,主流浏览器默认未开启,但是server端还是支持上比较好: 另外,这种单个连接上的pipeline msg,在需要有序返回的场景,也依赖于msg派发给逻辑线程池后的执行顺序,我今天读了workflow一点代码,逻辑线程池本身是mux+cond调度的,msgqueue派发时应该是无法指定线程的。所以如果支持pipeline并且按照msg的粒度put到msgqueue里就没法保证单个连接上的多个msg有序,但是如果msgqueue里是连接、连接派发给逻辑线程执行时再由逻辑线程判断当前连接上的msg队列,则能保证有序,并且msg加入到连接自己的队列时还可以判断当前msg是否为head,如果是head才需要去触发mux+cond唤醒并取得逻辑线程,如果不是head则无需触发。 http1.x这种每个请求不包括本次请求的session id所以依赖于回包顺序的比较恼火,server、client端的实现都比较秀发不友好 |
pipeline是我们一开始就放弃的功能。支持pipeline不如支持streaming。 |
对于静态资源这种需求,pipeline不给力,http2.0 streaming也不行,pipeline解决了client端发送时必须等上一个返回的这个RTT太久的空窗期问题,2.0则允许server端乱序响应、进一步提高了单个tcp信道的利用率,然后瓶颈就在tcp信道本身了,单个连接的拥塞控制以及tcp stream本身的数据顺序保障又跟pipeline以前的一个等一个类似、成为了新的障碍。 所以才会有3.0,真正解锁了c/s两端的并发无序能力以及单一tcp信道的限制,剩下的就交给3层了。 对于非静态资源的接口类请求,pipeline还是能提升性能的,而且万一人家client开启了、server却不支持,就尴尬了呢。。 |
我主要是觉得,pipeline是http1.1的一部分,如果不支持,相当于是功能缺失。 另外一个问题就是,如果不支持pipeline,http1.1 client端想提高吞吐时则只能通过更多连接数来解决,然后我们又来到了#906 ,需要继续优化连接数多了性能下降的问题:joy: |
哈哈哈。其实至今为止,你是第一个提出http pipeline需求的。而且,也不是业务中遇到,主要还是讨论一个http协议支持完整性的问题。其实也说明了实际业务中不太用到😂 |
golang标准库底层非阻塞但net.Conn提供的是阻塞读,读一个处理一个,所以自然就支持了完整的pipeline。 |
不支持问题不大,只是毕竟不太标准。。 |
改可以改,但有几个问题: |
其实框架层的消息分发与应用层的处理顺序,是两个不同的层,框架层默认无序了,是限制了自己的场景能力,因为应用层难再去让消息有序处理(应用层按消息id排序之类的成本更高),这相当于阉割了业务姿势。 之所以考虑这个,也是因为我在实现nbio的时候,最初也是无序,当我实现http,需要有序。甚至当我实现了http的有序后在其基础之上实现websocket时仍然是先无序地把websocket message无序地丢给用户,但是有时候,这样确实不好,因为限制了用户。 单个连接的数据有序到达、框架对其msg的有序派发应该是框架提供给应用层的基础保障,其他的无序与并发让应用层自己根据需要来做。 |
有序不意味着整个进程的逻辑单线程,只是单个连接的有序,多个连接仍然是均衡地从线程池中拿活跃线程来执行各自连接上的消息队列,比如我之前提到的我这里的实现:conn.Execute ,而且对于workflow的用cond调度的线程池来说,单个连接只有当前消息是head时才需要触发这个cond的操作,如果单个连接同时有10个msg、第一个尚未处理完,则其他9个msg入队列都不需要触发cond的操作,单个conn上的一个链表或者数组的O(1)操作+head判断,相比于cond,反倒可能节约一点性能 |
按照我上一楼说的方式,其实单个连接上的消息队列仍然是串行处理,但是每个消息丢给应用层时,应用层可以自行选择是否要把这个消息放到另外的线程池去异步处理从而并发 |
不会复杂太多的,只是每个Conn上挂个队列,每个msg解析出来判断是不是队列head,如果是就照常丢给msgqueue cond去给线程池里的一个线程处理,改动不会太大的 我没调试,cpp的读起来不太确认,这里应该是解析到一个完整消息后回调、丢给msgqueue然后逻辑线程池里去处理吧: |
如我前面解释的几条,真的不冲突,而是提供了更全面的基础能力,性能甚至不会下降反而因为减少了cond操作而提升,但数万连接时的性能下降我估计不是这个修改能提升上去的、可能还是有其他原因需要优化:joy: |
你说的都没错啊,我们可以提供这些选择,但问题是如果带来用户接口上的复杂性,结果反而损失更多的普通用户。这年头,用法复杂比功能欠缺更严重。除非我们能设计成对用户完全无感😂好像也不太容易。 |
单就这里讨论的实现上来讲,改动只限于框架层就可以了,用户接口不需要改,因为workflow已经自带了逻辑线程池这些,只是msgqueue派发到逻辑线程的时候的依据改变一下而已。我的nbio改造有序的时候,应用层接口也都没变,甚至,我直接是兼容标准库的,所以用户用我的框架只需要改下server启动的地方,那些hadler都不需要变,甚至那些基于标准库的主流框架也是只需要改下server启动的地方用我的就可以了。。。 这些都是分层的,每一层处理好自己的逻辑就可以了 |
hi,现在尝试给加的channel功能,可以满足你pipline的想法,不过现在用户协议不完善😂~~ |
等搞好了试试看效果 |
这个也先关掉了,要不要框架层支持有序主要看各位取舍了 |
尝试了下http client pipeline,同一个write发送两个http request的数据,代码如下:
output:
返回了一个响应后连接就被关闭了。
The text was updated successfully, but these errors were encountered: