Qi Space recently began to try to implement http3+QUIC protocol support
What is HTTP/3 and QUIC
HTTP2.0 is also based on the TCP protocol, and the tcp protocol has a strict order when processing packets
When one of the data packets encounters a problem, the TCP connection needs to wait for a packet to complete the retransmission before continuing. Although HTTP2.0 passes through multiple streams, the parallel content on a logical tcp connection is transmitted in multiple ways. , but there is no associated data in the middle, one after the other, the frames of the previous stream2 are not received, and the frames of the latter stream1 will also be blocked because of this
So Google's QUIC protocol switched from TCP to UDP
Custom connection mechanism
A tcp connection is identified by a quadruple, which is source ip, destination ip, source port, and destination port. Once an element changes, it will be disconnected and reconnected. Three handshakes are performed in the next time, resulting in a certain delay
There is no way in TCP, but based on UDP, the connection mechanism can be maintained in QUIC's own logic, which is no longer identified by a quadruple, but by a 64-bit random number as an ID, and UDP is no connected, so when the ip or port changes, as long as the ID remains the same, there is no need to re-establish the connection
Custom retransmission mechanism
In order to ensure reliability, tcp solves the problem of sequence and packet loss by using the sequence number and response mechanism.
If any packet with a sequence number is sent, it must be answered within a certain period of time. Otherwise, once it times out, the packet of this sequence number will be retransmitted and retransmitted through the adaptive retransmission algorithm (continuous adjustment by sampling round-trip time RTT)
However, there is an inaccuracy problem in the sampling of timeouts in TCP. For example, after sending a packet with serial number 100, it was found that it did not return, so it sent a 100, and returned ACK101 after a while. The client received it, but the round-trip time cannot be calculated. Whether the first or second is subtracted when the ACK arrives.
QUIC also has a sequence number, which is incremental. Any packet with a sequence number is only sent once, and 1 must be added next time, so that the calculation can be accurate.
But there is a problem, that is, how to know that packet 100 and packet 101 send the same content? quic defines an offset concept. Since QUIC is connection-oriented, just like TCP, it is a data stream. The data sent has an offset offset in this data stream. You can check the data sent there through the offset, so that only this offset packet does not come. , will be reissued. If it comes, it can still be spliced into a stream according to offset splicing.
non-blocking multiplexing
With a custom connection and retransmission mechanism, the multiplexing problem of HTTP2.0 above can be solved
Like HTTP2.0, multiple streams can be created on the same QUIC connection to send multiple HTTP requests. However, QUIC is based on UDP, and there is no dependency between multiple streams on a connection. In this way, if stream2 loses a UDP packet, followed by a UDP packet of stream3, although the packet of stream2 needs to be retransmitted, the packet of stream3 can be sent to the user without waiting.
custom flow control
TCP's flow control is through the sliding window protocol. QUIC's flow control also uses window_update to tell the peer the number of bytes it can accept. But QUIC's window is adapted to its own multiplexing mechanism, not only controlling the window on a connection, but also controlling the window of each steam in a connection.
In the TCP protocol, the starting point of the window of the receiver is the next packet to be received and ACKed. Even if all subsequent packets arrive and are placed in the cache, the window cannot be moved to the right, because the ACK mechanism of TCP is based on the accumulation of sequence numbers. Reply, once ACK has a sequence number, it means that the previous ones have arrived, so if the previous ones have not arrived, and the latter ones cannot be ACKed, it will cause the latter ones to arrive, and it may also time out and retransmit, wasting bandwidth.
QUIC's ACK is based on offsets. When each offset packet comes and enters the cache, it can be responded. After the response, it will not be retransmitted. The gap in the middle will wait for arrival or retransmission, and the starting position of the window is The maximum offset currently received, from this offset to the maximum buffer that the current stream can hold, is the size of the real window. Obviously, that is more accurate.
About Nginx Quic Technology Preview
Nginx officially launched a preview version of nginx-quic to support the new QUIC+HTTP/3 transport protocol. nginx-quic is based on the IETF QUIC draft and is maintained in the Nginx development branch, isolated from the stable and trunk branches.
After months of intense development, it is now releasing a beta preview, releasing a public beta for its interoperability testing, problem feedback and community code contributions. At the same time, nginx also released a demo site (quic.nginx.org) for functional demonstration.
deploy
For this exploration, I have prepared a repository called nginx-enhance-module to include some commonly used modules and nginx-quic, we use the following command to initialize this module:
sudo apt install openssl libssl-dev libxml2 libxml2-dev libxslt1.1 libxslt1-dev libpcre3-dev zlib1g-dev -y
sudo apt install mercurial
sudo apt install python3-pip
git clone https://github.com/jack9603301/nginx-enhance-module
cd nginx-enhance-module
sudo python3 -m pip install -r requirements.txt
./download_dependency.py
We can use the above command to get nginx-enhance-module
the included modules. Then start preparing to compile the basic dependencies:
cd depends
git clone https://github.com/ivmai/libatomic_ops.git
cd libatomic_ops
./autogen.sh
./configure --prefix=/usr
make
sudo make install
cd ..
cd pcre
./configure --prefix=/usr/local
make
sudo make install
cd ../LuaJIT
make
sudo make install PREFIX=/usr/local
echo "/usr/local/lib" > /etc/ld.so.conf.d/usr_local_luajit_lib.conf
sudo ldconfig
export C_INCLUDE_PATH="/usr/local/include/luajit-2.0/"
export CXX_INCLUDE_PATH="/usr/local/include/luajit-2.0/"
export CPLUS_INCLUDE_PATH="/usr/local/include/luajit-2.0/"
cd ../../modules/boringssl
mkdir build
cd build
cmake ..
make
cd ../..
cp boringssl/build/crypto/libcrypto.a boringssl/build/ssl/libssl.a boringssl/.openssl/lib
cd boringssl/.openssl
ln -s ../include .
cd ../..
cd ../depends/nginx-quic
./auto/configure --prefix=/usr/local/nginx --user=www --group=www --error-log-path=/www/logs/nginx-error.log --conf-path=/www/services/nginx/nginx.conf --with-http_stub_status_module --with-stream --with-stream_ssl_module --with-http_ssl_module --with-http_dav_module --add-module=../../modules/nginx-dav-ext-module --with-stream --with-stream_ssl_module --with-http_v2_module --with-stream --with-stream_ssl_module --with-stream --with-stream_ssl_module --with-stream --with-stream_ssl_module --with-http_realip_module --with-stream --with-stream_ssl_module --with-pcre --with-libatomic --with-threads --with-file-aio --with-poll_module --with-select_module --with-stream --with-stream_ssl_module --with-stream --with-stream_ssl_module --add-module=../../modules/ngx_devel_kit --add-module=../../modules/naxsi/naxsi_src --add-module=../../modules/nginx-module-vts --add-module=../../modules/ngx_brotli --add-module=../../modules/nginx-sticky-module-ng --add-module=../../modules/headers-more-nginx-module --with-cc-opt='-I/root/nginx-enhance-module/modules/boringssl/include -O0 -fno-common -fno-omit-frame-pointer -DNGX_QUIC_DRAFT_VERSION=29' --with-ld-opt='-L/root/nginx-enhance-module/modules/boringssl/build/ssl -L/root/nginx-enhance-module/modules/boringssl/build/crypto' --with-http_v3_module --with-http_quic_module --with-stream_quic_module --build=$(hg tip | head -n 1 | awk '{ print $2 }')
make
sudo make install
configure
Next, you need to modify the configuration, such as:
upstream qhjack-https {
server 66.42.99.20:443 max_fails=10 fail_timeout=120s;
server 45.32.64.248:443 max_fails=10 fail_timeout=120s;
server 45.76.71.198:443 max_fails=10 fail_timeout=120s;
}
server {
listen 80 default_server;
listen [::]:80 default_server;
listen 443 default_server quic http3 reuseport;
listen 443 default_server ssl http2;
listen [::]:443 default_server quic http3 reuseport;
listen [::]:443 default_server ssl http2;
server_name www.qhjack.cn qhjack.cn;
#limit_req zone=server burst=10 nodelay;
#limit_req_status 503;
#limit_req_log_level error;
#开启服务器推送
http2_push_preload on;
# 开启HTTP/3
#add_header alt-svc 'quic=":443"; ma=86400; v="46,43",h3-27=":443";h3-23=":443"; ma=86400,h3-Q050=":443"; ma=86400,h3-Q049=":443"; ma=86400,h3-Q048=":443"; ma=86400,h3-Q046=":443"; ma=86400,h3-Q043=":443"; ma=86400,h3-T050=":443"; ma=86400';
add_header alt-svc '$http3=":443"; ma=86400';
add_header QUIC-Status $quic;
quic_initial_max_streams_bidi 100;
quic_retry on;
# enable 0-RTT
ssl_early_data on;
ssl_session_tickets on;
# 开启HTTPS/SSL和HSTS
add_header Strict-Transport-Security "max-age=15768000;preload" always;
ssl_certificate /etc/letsencrypt/live/qhjack.cn/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/qhjack.cn/privkey.pem;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4:!DH:!DHE;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /etc/letsencrypt/live/qhjack.cn/fullchain.pem;
if ($scheme = http) {
return 301 https://www.qhjack.cn$request_uri;
}
if ($host = "qhjack.cn") {
return 301 https://www.qhjack.cn$request_uri;
}
#计算Cookie,判断是否缓存
set $wordpress_auth 0;
if ($http_cookie ~ ";(wordpress_logged_in_[a-z0-9]{32});") {
set $wordpress_auth 1;
}
# POST requests and urls with a query string should always go to PHP
if ($request_method = POST) {
set $wordpress_auth 1;
}
if ($query_string != "") {
set $wordpress_auth 1;
}
# Don't cache uris containing the following segments
if ($request_uri ~* "/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml") {
set $wordpress_auth 1;
}
# Don't use the cache for logged in users or recent commenters
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $wordpress_auth 1;
}
location ~ \.(gif|jpg|jpeg|png|bmp|swf|js|css|pdf|doc)$ { #指定缓存文件类型
expires 7d; #设置浏览器过期时间
root /www/services/nginx/cache/proxy_store;
proxy_pass https://qhjack-https;
proxy_set_header Host $host;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_next_upstream_tries 5;
proxy_store on; # 开启镜像加速功能
proxy_store_access user:rw group:rw all:rw; #缓存读写规则
}
location ~* /wp-content/plugins/versionpress/admin/public/.*$ {
allow all;
}
location ~* /wp-content/plugins/versionpress/.*$ {
deny all;
}
location ~* /wp-content/vpdb/.*$ {
deny all;
}
location ~* /wp-content/vpbackups/.*$ {
deny all;
}
location ~* /\.git/.*$ {
deny all;
}
location / {
proxy_pass https://qhjack-https;
proxy_set_header Host $host;
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
proxy_next_upstream_tries 5;
proxy_cache_key "$scheme$request_method$host$request_uri$http_cookie";
proxy_cache_use_stale error timeout invalid_header http_500;
proxy_no_cache $wordpress_auth;
proxy_cache_methods GET HEAD;
proxy_cache_min_uses 1;
proxy_cache_valid 200 1d;
proxy_cache_valid 404 500 502 503 504 302 301 0s;
proxy_cache_valid any 1d;
proxy_cache qhjack_proxy_cache;
etag on;
proxy_pass_header "X-Accel-Redirect";
proxy_pass_header "X-Accel-Expires";
proxy_pass_header "X-Accel-Charset";
proxy_pass_header "X-Accel-Expires";
proxy_pass_header "X-Accel-Limit-Rate";
}
charset utf-8;
error_log /www/logs/qhjack/proxy/error.log;
access_log /www/logs/qhjack/proxy/access.log access buffer=1k;
}
First of all, you need to listen
open the http3
options and reuseport
, it should be noted that reuseport
it can only appear once in the configuration, otherwise an error will be reported
The following options also need to be set:
# 开启HTTP/3
add_header alt-svc '$http3=":443"; ma=86400';
add_header QUIC-Status $quic;
quic_initial_max_streams_bidi 100;
quic_retry on;
# enable 0-RTT
ssl_early_data on;
ssl_session_tickets on;
have to be aware of is:
$quic
The variable holds the state information of QUIC. If it is a QUIC transmission, this variable isquic
, otherwise, it is an empty variable$http3
The variable holds the supported http3 protocol standard
run
You only need to use the following command to run, and other configurations are the same as the nginx release version :
sudo systemctl restart nginx
Part of the content of this article comes from https://www.cnblogs.com/chenjinxinlove/p/10104854.html
This article is simultaneously shared on the blog "Starting Space" (other).
If there is any infringement, please contact [email protected] to delete it.
This article participates in the " OSC Yuanchuang Project ", you are welcome to join and share with us.