Background
HTTP/3 is the third major version of the Hypertext Transfer Protocol used to exchange information on the World Wide Web, complementing the widely-deployed HTTP/1.1 and HTTP/2.
Both HTTP/1.1 and HTTP/2 use TCP as their transport. HTTP/3 uses QUIC, a transport layer network protocol which uses user space congestion control over the User Datagram Protocol (UDP). The switch to QUIC aims to fix a major problem of HTTP/2 called “head-of-line blocking”: because the parallel nature of HTTP/2’s multiplexing is not visible to TCP’s loss recovery mechanisms, a lost or reordered packet causes all active transactions to experience a stall regardless of whether that transaction was impacted by the lost packet. Because QUIC provides native multiplexing, lost packets only impact the streams where data has been lost.
How to send HTTP/2 and HTTP/3 request from OpenResty/Nginx?
In fact, it’s difficult to support HTTP/2 and HTTP/3, because cosocket has below limitations:
tcpsock:sslhandshake
doesn’t support the ALPN.- cosocket instance (connection) is bound to a specific HTTP downstream request, i.e. connection could not be shared globally, which disables HTTP2/HTTP3 multiplexing and concurrency then.
req is a golang library: Simple Go HTTP client with Black Magic.
Highlights:
- unique interface for all HTTP versions
- auto HTTP version selection
- easy download and upload
Why not encapsulate it so that we could reuse it in openresty?
lua-resty-ffi provides an efficient and generic API to do hybrid programming in openresty with mainstream languages (Go, Python, Java, Rust, Nodejs).
lua-resty-ffi-req = lua-resty-ffi + req
Check this repo for source code:
https://github.com/kingluo/lua-resty-ffi-req
Demo
simple get
|
|
Output:
|
|
request body writer and response body reader
|
|
HTTP3
Install Nginx HTTP3 version:
https://www.nginx.com/blog/binary-packages-for-preview-nginx-quic-http3-implementation/
# nginx.conf
http {
# for better compatibility it's recommended
# to use the same port for quic and https
listen 8443 http3 reuseport;
listen 8443 http2 ssl reuseport;
ssl_certificate /opt/certs/ca.crt;
ssl_certificate_key /opt/certs/ca.key;
ssl_protocols TLSv1.3;
location / {
if ($arg_http3 = true) {
add_header Alt-Svc 'h3=":8443"; ma=86400';
}
#proxy_pass http://httpbin_backend;
#proxy_http_version 1.1;
#proxy_set_header Connection "";
return 200 ok;
}
}
Test Alt-Svc
:
|
|
Output:
|
|
Auto HTTP version selection
req uses TLS ALPN and Alt-Svc
header to do auto HTTP version selection.
HTTP1 to H2C (HTTP2 Clear Text)
This method is not supported yet.
HTTP2 ALPN
HTTP3 Alt-Svc
Redirect to the same site:
Redirect to a different site:
Benchmark
Due to golang http client implementation, lua-resty-ffi-req has only 70% of the performance of lua-resty-http, and it consumes 30% more cpu than lua-resty-http.
The performance is not that good yet, but there is room for improvement.
It is still worth sacrificing some performance for the ecosystem:
- No need to reinvent the wheel, especially when the wheel is big
- Cover maximum functionalities
- No need to bugfix yourself, because there is many contributors for popular open source project
FYI, here is the flamegraph of lua-resty-ffi-req (open in new tab page to browse the flamegraph svg):
Conclusion
With lua-resty-ffi, you could use your favorite mainstream programming language, e.g. Go, Java, Python, Rust, or Node.js, to do development in Openresty/Nginx, so that you could enjoy their rich ecosystem directly.
Welcome to discuss and like my github repo: