zoukankan      html  css  js  c++  java
  • Quick UDP Internet Connections 让互联网更快的协议,QUIC在腾讯的实践及性能优化

    https://mp.weixin.qq.com/s/44ysXnVBUq_nJByMyX9n5A

    让互联网更快:通往QUIC之路

    QUIC(Quick UDP Internet Connections)是一种默认加密的新互联网传输协议,它提供了多项改进,旨在加速HTTP传输并使其更加安全,目标是想最终取代TCP和TLS协议。在本文中,我们将概述QUIC协议的一些关键特性和它们给Web带来的好处,以及支持这一全新协议过程中遇到的一些挑战。

    实际上有两个协议共享QUIC这个名称,其一是“Google QUIC”(下称“gQUIC”),是Google工程师几年前设计的原始协议,经过多年的实验,现已被IETF(Internet Engineering Task Force)采用并正在进行标准化。

    另一个是“IETF QUIC”(下称“QUIC”),由于和gQUIC有着显著的差别,因此可以认为它是一个单独的协议。通过许多组织和个人的协作努力,从数据传输格式到握手和HTTP映射,QUIC改进了原有的gQUIC设计,但共同目标仍然是尽可能让互联网变得更快、更安全。那么,QUIC都提供了哪些改进呢?

    内置的安全和性能机制

     

    QUIC与现在常用的TCP相比,一个彻底的改变是它的设计目标:默认提供安全的传输协议。QUIC通过在传输层提供安全特性(如身份验证和加密)来实现,而以往这些功能通常由更高层的协议(如TLS)处理。

    最初的QUIC握手方式结合了TCP经典的三次握手与TLS 1.3对端点的认证以及加密参数的协商。对于熟悉TLS协议的人来说,QUIC其实是取代了TLS记录协议,保留了TLS握手协议。

    这不仅确保了连接始终被认证和加密,而且还使得初始连接建立更快:与TCP和TLS 1.3握手相结合所需的两次往返相比,典型的QUIC握手只需要在客户端和服务器之间完成一次往返。

    不仅如此,QUIC还加密了可能被中间设备滥用而干扰连接的其它元数据。例如,当使用连接迁移时,被动式攻击可以使用数据包序号来关联多个网络路径上的用户活动(见下文)。通过加密数据包序号,QUIC可以确保它们不能被连接端点之外的任何实体关联活动。

    加密也可以成为僵化问题(ossification)的有效补救措施,这使得协议的灵活性(例如能够协商不同版本的协议)由于错误的假设而在实践中不能被使用。僵化问题导致了TLS 1.3部署的长期延迟,而在几次更改(防止中间设备错误地阻止新版本的TLS协议)被采用之后才使得部署变得可能。

    队头阻塞

     

    HTTP/2提供的重要改进之一是能够将不同的HTTP请求复用同一个TCP连接,这使得HTTP/2应用程序可以并行处理请求并更好地利用可用的网络带宽。

    这是一项重大改进,如果想要同时处理多个HTTP/1.1请求(例如当浏览器需要同时获取CSS和JavaScript资源渲染网页时),应用程序需要启动多个TCP + TLS连接。创建新连接需要重复多次初始握手,以及初始拥塞窗口加速,这意味着网页的渲染速度会降低,而多路复用HTTP则避免了这些问题。

    然而,它也有一个缺陷,由于多个请求/响应使用相同的TCP连接传输,所以它们都受到数据包丢失的影响(例如由于网络拥塞),即使丢失的数据仅涉及单个请求。这种现象被称为“队头阻塞”。

    QUIC更进一步为多路复用提供了良好的支持,使得不同的HTTP流可以依次映射到不同的QUIC传输流,但是它们仍然共享相同的QUIC连接,因此不需要进行额外的握手,并且共享拥塞状态, QUIC流是独立传递的,因此在大多数情况下,一个流的数据包丢失不会影响其它传输流。

    这可以大大减少例如渲染完整网页(包括CSS、JavaScript、图片和其它类型资源)所需的时间,特别是在通过具有较高丢包率的高拥塞网络时。

    这很简单,呃?

     

    为了实现这些目标,QUIC协议需要打破许多网络应用程序认为理所当然的一些假设,这可能使QUIC的实现和部署更加困难。

    QUIC的设计基于UDP数据报来简化部署,同时避免部分网络设备丢弃未知协议数据包的问题,因为绝大多数设备已经支持UDP。这也允许了QUIC在用户空间中实现,例如,浏览器能够实现新的协议功能并发送给用户,而无需等待操作系统更新。

    然而,尽管预期的目标是避免破坏,但它仍在防止滥用并将数据包路由到正确的端点方面极具挑战性。

    通过一个NAT问题深入理解

     

    典型的NAT路由器可以使用传统的4元组(源IP地址和端口,目的IP地址和端口)跟踪通过它们的TCP连接,并通过观察传输的TCP SYN、ACK和FIN数据包,可以检测到连接的建立和终止。这样可以精确地管理NAT绑定的生命周期和内外部IP地址和端口的关联关系。

    但是这在QUIC还不能实现,因为目前部署的NAT路由器不了解QUIC,因此它们通常会回退到默认配置,然后对UDP流处理的不太准确,通常会使用任意的,有时非常短的超时,可能会影响长时间运行的连接。

    当NAT重新绑定时(例如超时),NAT外部的端点将看到来自与最初建立连接时观察到的源端口不同的数据包,这使得仅使用4元组无法跟踪连接。

    不仅仅是NAT!QUIC旨在提供的功能之一称为“连接迁移”,允许QUIC端点随意迁移到不同IP地址和网络路径的连接。例如,当已知的Wi-Fi网络可用时(例如,当用户进入他们喜欢的咖啡店时),移动客户端能够在蜂窝数据网络和Wi-Fi之间迁移QUIC连接。

    QUIC试图通过引入连接ID的概念来解决这个问题:一个由QUIC数据包携带的可变长度的opaque blob,可用于标识连接。端点可以使用此ID来跟踪它们负责的连接,而无需检查4元组(实际上,可能有多个ID标识相同的连接,例如,为了避免在使用连接迁移时链接不同的路径, 但这种行为是由端点而不是中间设备控制的)。

    但是,这也给使用anycast寻址和ECMP路由的网络运营商带来了问题,其中单个目标IP地址可能潜在地识别数百甚至数千个服务器。由于这些网络使用的边缘路由器还不知道如何处理QUIC流量,因此可能会发生UDP数据包虽然属于相同的QUIC连接(即具有相同的连接ID)但具有不同的4元组(由于 NAT重新绑定或连接迁移)被路由到不同的服务器,从而破坏了连接。

    为了解决这个问题,网络运营商可能需要采用更智能的4层负载均衡解决方案,它们可以通过软件实现,而无需接触边缘路由器即可部署(参见Facebook的Katran项目)。

    QPACK

     

    HTTP/2带来的另一个好处是头部压缩(header compression或HPACK),它允许HTTP/2端点通过从HTTP请求和响应中删除冗余来减少网络传输的数据量。

    特别是,在其它技术中,HPACK使用之前的HTTP请求(或响应)发送(或接收)的报头动态填充表项,允许端点在新请求(或响应)中引用先前遇到的报头,而不是再次传输。

    HPACK的动态表需要在编码器(发送HTTP请求或响应的一方)和解码器(接收它们的一方)之间同步,否则解码器将无法解码它接收的内容。

    对于TCP上的HTTP/2,这种同步是透明的,因为传输层(TCP)负责以与发送它们相同的顺序提供HTTP请求和响应,更新表的指令可以简单地由编码器作为部分请求(或响应)本身,使得编码非常简单。但对于QUIC来说,这有些复杂。

    QUIC可以独立地在不同的流上处理多个HTTP请求(或响应),这意味着虽然就单个流而言它负责按顺序交付数据,但是跨多个流是没有顺序保证的。

    举例来说,如果客户端通过QUIC流A发送HTTP请求A,然后通过流B发送请求B,由于网络中的数据包重新排序或丢失,可能会发生服务器在请求A之前接收到请求B,并且请求B被编码引用了来自请求A的头,那么服务器将无法解码它,因为它还没有接收到请求A。

    在gQUIC协议中,通过简单地在同一gQUIC流上串行化所有HTTP请求和响应头(不是body)来解决这个问题,这意味着无论如何都会按顺序传递报头。这是一个非常简单的方案,可以实现重用大量现有的HTTP/2代码,但另一方面它增加了QUIC期望减少的队头阻塞。因此,IETF QUIC工作组设计了一组HTTP和QUIC之间(“HTTP/QUIC”)的新映射关系,以及称为“QPACK”的新报头压缩方案。

    在HTTP/QUIC映射和QPACK规范的最新草案中,每个HTTP请求/响应交换使用自身的双向QUIC流,因此没有队头阻塞。此外,为了支持QPACK,每端需要额外创建两个单向QUIC流,一个用于向另一个对等体发送QPACK表更新,另一个用于确认另一方接收的更新。这样,QPACK编码器只有在解码器明确确认之后才能使用动态表引用。

    应对反射攻击

     

    基于UDP的协议中的一个常见问题是它们容易受到反射攻击,攻击者通过源IP地址欺骗(它们看起来像是发送自受害者)诱使一些服务器向第三方受害者发送大量数据。

    当服务器发送的响应大于收到的请求时,这种攻击非常有效,这种情况我们称为“放大”。

    TCP通常不受这种攻击影响,因为在握手期间发送的初始数据包(SYN,SYN+ACK,...)具有相同的长度,所以它们不具有任何放大的潜力。

    另一方面,QUIC的握手是非常不对称的:像TLS一样,在第一次传输中,QUIC服务器通常发送自己的证书链,这可能非常大,而客户端只需要发送几个字节(QUIC包中嵌入的TLS ClientHello消息)。因此,客户端发送的初始QUIC数据包必须填充到特定的最小长度(即使数据包的实际内容要小得多)。然而,这种缓解仍然不够,因为常见的服务器响应会跨多个数据包,可能仍远远大于客户端填充后的数据包。

    QUIC协议还定义了一种显式的源地址验证机制,服务器先不发送长响应,而是仅发送一个小得多的retry数据包,其中包含一个唯一的加密令牌,然后客户端必须在新的初始数据包中回应它。这样,服务器就更方便确认客户端不会进行源IP地址欺骗(因为它收到了retry数据包),并且可以完成握手。这种缓解方法的缺点是它将初始握手持续时间从单次往返增加到两次。

    另一种解决方案通过减少服务器响应降低反射攻击效果,例如采用ECDSA证书(通常比RSA小很多)。此外,也可以尝试通过现成的压缩算法(如zlib和brotli)压缩TLS证书,这也是gQUIC最初引入的特性,但目前在TLS中还不可用。

     

    UDP性能

     

    QUIC经常出现的问题之一是已经部署的硬件和软件无法识别它。前面介绍了QUIC如何尝试解决路由器等网络中间设备问题,但另一个可能存在的问题是在QUIC端点上通过UDP发送和接收数据的性能。多年来,很多工作旨在优化TCP,包括在软件(如操作系统)和硬件(如网络接口)中构建卸载功能,但目前这些功能都不适用于UDP。

    然而,QUIC具备这些功能只是时间问题。以最近在Linux上实现UDP通用分段卸载(Generic Segmentation Offloading)的工作为例,这将允许应用程序在用户空间和内核空间网络堆栈之间汇集和传输多个UDP段转换为单个(或者近似)UDP段。此外,还有在Linux上添加zerocopy套接字支持的例子,这将使应用程序避免将用户空间内存复制到内核空间。

    结论

     

    与HTTP/2和TLS 1.3一样,QUIC将提供多项旨在提高网站性能和安全等方面的新功能,目前IETF工作组计划在今年年底前提供QUIC规范的第一版。

    原文链接:

    https://blog.cloudflare.com/the-road-to-quic/

    https://mp.weixin.qq.com/s/_RAXrlGPeN_3D6dhJFf6Qg

    作者|罗成编辑|小智本文主要介绍 QUIC 协议在腾讯内部及腾讯云上的实践和性能优化。欲了解 QUIC 协议产生的背景和核心特性,可阅读今日二条推文。写在前面

    如果你的 App,在不需要任何修改的情况下就能提升 15% 以上的访问速度。特别是弱网络的时候能够提升 20% 以上的访问速度。

    如果你的 App,在频繁切换 4G 和 WIFI 网络的情况下,不会断线,不需要重连,用户无任何感知。如果你的 App,既需要 TLS 的安全,也想实现多路复用的强大。

    如果你刚刚才听说 HTTP2 是下一代互联网协议,如果你刚刚才关注到 TLS1.3 是一个革命性具有里程碑意义的协议,但是这两个协议却一直在被另一个更新兴的协议所影响和挑战。

    如果这个新兴的协议,它的名字就叫做“快”,并且正在标准化为新一代的互联网传输协议。

    你愿意花一点点时间了解这个协议吗?你愿意投入精力去研究这个协议吗?你愿意全力推动业务来使用这个协议吗?

    QUIC 在腾讯的实践

    腾讯安全云网关 (STGW) 和腾讯云负载均衡器(Cloud Load Balance)在 2017 年 7 月份就已经在服务端上支持了 Quic 协议,在工程实现上也有很多优化点,同时在生产环境中也取得了较好的效果。相比现在几个开源的方案,STGW 的实现主要有如下几个优点:

    1. 高性能。

      • 复用 Nginx 全异步事件驱动框架。

      • 私钥代理计算集群加速签名计算。

      • 全局缓存提速,减少计算量的同时,提升访问速度。

    2. 强大的功能。

      • 支持 Nginx 现有全部模块指令,丰富的第三方模块。

      • 复用 Nginx 模块框架,非常灵活地新增第三方功能。

    3. 稳定性。

      • 代码完全自主可控。

      • 正在经受腾讯亿万级并发流量的考验。

    同时我们也在腾讯很多业务包括 QQ 空间、WEB 游戏页面、腾讯云 CLB 上灰度支持了 QUIC 协议。详细的收益数据可以参考第 6 章。

    QUIC 线下测试方案

    在决定使用 QUIC 协议之前,我们需要对 QUIC 协议的特性及性能做一个全面的测试,如何测试呢?这里简单说一下测试方案。

    需要特别说明的测试是在 2016 年底进行的,目前所有域名已经失效,无法再进行测试。

    页面构造

    根据 httparchive.org 的统计,构造了如下页面:

    测试环境

    手机:华为 mate9 
    
    User-Agent:MHA-AL00 Build/HUAWEIMHA-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.91 Mobile Safari/537.36
    
    操作系统:Android 7.0
    
    服务端 QUIC 程序:caddy 0.9.4

     

    网站和客户端分布如下:

    QUIC 测试框架

    • ①表示客户端主动发起的用户请求。

    • ②表示从 html 里发出的资源请求。

    • ③表示数据上报请求。

    测试流程

    整个测试流程通过 python 脚本和 adb shell 工具自动化进行。其中移动端和 PC 端的控制流程有所区别。分别简介如下:

     移动端测试流程

    准备事项:

    1. 打开手机的 usb 调试选项。

    2. 在 PC 端安装 adb。

    3. 在 PC 上通过 USB 连接手机,确保能够通过 adb  devices 命令发现设备。

    4. 在服务端配置 cache-control: no-cache, no-store。禁止客户端缓存。

    自动化测试流程如下:

    1. 启动 android chrome。

    2. 访问 https://www.helloworlds.cc。

    3. 待页面加载完后会触发 onload 事件,将各个时间点上报。

     PC 端流程

    PC 端不需要 adb,使用 webbrowser 模块控制 chrome 完成即可。

    测试结论

    由于公司内网的 WIFI 环境不稳定,多次测试发现数据跳动较大,4G 环境下的数据更加稳定可靠,所以主要结论参考 4G 网络下的数据。

    QUIC 的优势非常明显,即使在元素比较少(12 个元素)的情况下,相比 HTTP 也能提升 9%,相比 HTTP2 提升 42%,相比 HTTPS 提升 52%。

    在页面元素增多的情况下,QUIC 的优势就更加明显,相比 HTTP 提升 36%,相比 HTTP2 提升 47%,相比 HTTPS 提升 64%。

    QUIC 性能优化

    QUIC 的特性虽然比较先进,但是实现起来却非常复杂,在工程实现方面也有很多优化的空间。比如如何提升 0RTT 成功率,减少服务端的 CPU 消耗量,实现连接迁移和动态的拥塞控制算法等。

    提升 0RTT 成功率

    安全传输层虽然能够实现 0RTT,优势非常明显。但问题是,不是每一次连接都能实现 0RTT,对于我们的客户端和服务端来讲,如何最大程度地提升 0RTT 的成功率?

    0RTT 能实现的关键是 ServerConfig。就像 TLS session resume 实现的关键是 session id 或者 session ticket 一样。

    ServerConfig 到达服务端后,我们根据 ServerConfig ID 查找本地内存,如果找到了,即认为这个数据是可信的,能够完成 0RTT 握手。

    但是会有两个问题:

    1. 进程间 ID 数据无法共享。

    2. 多台服务器间的 ID 数据无法共享。

    明确了问题,那工程层面就需要实现多进程共享及分布式多集群的 ID 共享。

    SeverConfig Cache 集群

    Stgw 在生成 ServerConfig ID 和内容时,会存储到全局的 Cache 集群。用户握手请求落到任意一台 STGW 机器,从全局 Cache 集群都能找到相应的内容,实现 0RTT 握手。

    加密性能的优化 签名计算

    QUIC 实现 0RTT 的前提是 ServerConfig 这个内容签名和校验都没有问题。由于 ServerConfig 涉及到 RSA 签名或者 ECDSA 签名,非常消耗我们的 CPU 资源。根据之前的测试数据,RSA 私钥签名计算会降低 90% 的性能。

    那如何优化呢?使用 RSA 或者 ECDSA 异步代理计算。核心思路也是三点:

    1. 算法分离。剥离私钥计算部分,不让这个过程占用本地 CPU 资源。

    2. 异步执行。算法剥离和执行异步的,上层服务不需要同步等待这个计算过程的完成。

    3. 并行计算。我们使用配置了专用硬件的私钥计算集群来完成私钥计算。

    架构如下图所示:

    签名代理计算

     对称加密的优化

    相比非对称密钥交换算法来讲,对称加密算法的性能非常卓越(好 1 到 2 个数量级),但是如果应用层传输内容较大的话,特别是移动端的 CPU 计算能力较弱,对称加密算法对性能的影响也不容忽视。

    表格 1 常用对称加密算法性能比较

    如何优化呢?通过异步代理的方式显然不可能。原因是:

    会极大降低用户访问速度。由于应用层的每一个字节都需要对称加解密,使用异步的方式实现会严重降低加解密的实时性。

    那有没有同步的优化方式呢?有。类似 SSL 硬件加速卡,intel 针对 AES 算法实现硬件加速,并将它集成到了 CPU 指令里。

    AES-NI 指令

    AES-NI 是 intel 推出的针对 AES 对称加密算法进行优化的一系列指令,通过硬件计算实现计算速度的提升。

    如何测试 AES-NI 的性能呢?

    通过环境变量

    aes-ni: OPENSSL_ia32cap="~0x200000200000000" openssl speed -elapsed -evp aes-128-gcm 或者在代码里将 crypto/evp/e_aes.c # define AESNI_CAPABLE (OPENSSL_ia32cap_P[1]&(1<<(57-32))) 进行设置。

    aesni 对性能的提升约 20%, 由 4.3W 提升到 5.1W。

    这里需要注意的是,如果需要单独使用 openssl 的 API 进行 AES 对称加解密,最好使用 aes evp API,这样才会默认开启 AES-NI 指令。

    chacha20-poly1305

    chacha20-poly1305 是由 Dan Bernstein 发明,并且由 google 推出的一种带身份认证的对称加密算法。其中 chacha20 是指对称加密算法,poly1305 指身份认证算法。这个算法是对没有 AES 硬件加速功能的移动平台的补充,比如 ARM 芯片。

    从 google 公布的数据来看,chacha20-poly1305 能够提升 30% 以上的加解密性能,节省移动端耗电量。当然,如果手机端支持 AES-NI 指令的话,chacha20 就没有优势了。

    Openssl 在 1.1.0 版本中正式支持了 chacha20-poly1305。

    连接迁移 (Connection Migration) 的实现

    那 STGW 服务端如何实现的呢?我们在 CLB 四层转发层面实现了根据 ID 进行哈希的负载均衡算法,保证将相同 ID 的 QUIC 请求落到相同的 CLB7 层集群上,在 CLB7 上,我们又会优先根据 ID 进行处理。

    图示如下:

    QUIC 连接迁移

    如上图所述,客户端最开始使用 4G 移动网络访问业务,源 IP 假设为 IP1,整个访问流程使用蓝色线条标识。

    当用户进入 WIFI 网络时,源 IP 发生了变化,从 IP1 切换到了 IP2,整个访问流程使用绿色线条标识。由于接入的 CLB4 有可能发生变化,但整个 CLB 集群统一使用 QUIC Connection ID 调度,只要 QUIC 连接的 ID 没有发生变化,能够将该请求调度到相同的 CLB7 层机器上。

    同一台 CLB7 保存了相同的 Stream 及 Connection 处理上下文,能够将该请求继续调度到相同的业务 RS 机器。

    整个网络和 IP 切换过程,对于用户和业务来讲,没有任何感知。

    动态的流量控制和拥塞控制

    STGW 在连接和 Stream 级别设置了不同的窗口数。

    最重要的是,我们可以在内存不足或者上游处理性能出现问题时,通过流量控制来限制传输速率,保障服务可用性。

    性能统计

    STGW 针对 QUIC 的线上使用情况进行了很多的变量统计和分析,包括 0RTT 握手成功率,握手时间,密码套件使用分布,QUIC 协议版本,stream 并发数量等。

    这些统计变量能够为我们的协议优化提供更加精细的数据支撑。

    QUIC 线上灰度数据

    QUIC 目前已经在 STGW 上线运行。我们针对腾讯几个重要域名(包括 QQ 黄钻页面,游戏页面)进行了灰度实验。

    Qzone QUIC 页面

    如上图所示,图中红色箭头指向的绿色标识表示该页面使用了 QUIC 协议。

    灰度实验的效果也非常明显,其中 quic 请求的首字节时间 (rspStart) 比 http2 平均减少 326ms, 性能提升约 25%; 这主要得益于 quic 的 0RTT 和 1RTT 握手时间,能够更早的发出请求。

    此外 quic 请求发出的时间 (reqStart) 比 h2 平均减少 250ms; 另外 quic 请求页面加载完成的时间 (loadEnd) 平均减少 2s,由于整体页面比较复杂, 很多其它的资源加载阻塞,导致整体加载完成的时间比较长约 9s,性能提升比例约 22%。

    上述数据有两个问题,仅供参考:

    1. 由于我们的页面并没有全部改造成 QUIC 协议,所以性能数据应该还可以进一步提升。

    2. 每个业务的页面构成不一样,提升的性能数据也会有差别。

    CLB-QUIC-DEMO

    前面提到的 QUIC 实践和优化都是针对服务端。为了方便广大开发者进一步了解 QUIC 在客户端的使用,我们提供了一个安卓客户端的 DEMO,仅供参考。

    DEMO 已经在 github 上开源,地址如下:

    https://github.com/tencentyun/clb-quic-demo

    DEMO 的主要目的有两个:

    1. 简单说明一下在客户端使用 QUIC。

    2. 简单对比 HTTP2 和 QUIC 的性能差别。

    如果有用户想使用 QUIC 协议,客户端做一下改造,服务端直接使用腾讯云 CLB 负载均衡器就能实现了。

    如前所述,CLB 在协议计算性能和访问速度、安全性能方面,做了非常多优化。

    结    论

    QUIC 协议非常复杂,因为它做了太多事情:

    为了实现传输的可靠性,它基本上实现并且改进了整个 TCP 协议的功能,包括序列号,重传,拥塞控制,流量控制等。

    为了实现传输的安全性,它又彻底重构了 TLS 协议,包括证书压缩,握手消息,0RTT 等。虽然后续可能会采用 TLS1.3 协议,但是事实上是 QUIC 推动了 TLS1.3 的发展。

    为了实现传输的并发性,它又实现了 HTTP2 的大部分特性,包括多路复用,流量控制等。

    虽然如此复杂,但是 QUIC 作为一个新兴的协议,已经展现了非常强大的生命力和广阔的前景。

    目前国内外除了 Google 大规模采用外,还鲜有其他互联网公司使用。STGW 作为腾讯的安全云网关,我们有责任,有义务对业界先进的标准协议提供支持和优化。同时腾讯云也是国内第一家支持 QUIC 协议的云厂商,因为这个协议能切实改善客户端的访问速度和终端用户体验。

    我们不仅在服务端实现了 Quic 协议的支持,优化了 QUIC 协议方面的性能问题,同时也希望通过自己一些经验的分享,推动 QUIC 协议的发展,构造一个更加安全更加快速的互联网世界。

    Let’Quic,  Make Web Faster。

  • 相关阅读:
    Rocket
    Rocket
    Rocket
    Rocket
    POJ 1849 树的直径 Two
    SGU 495 Kids and Prizes
    HDU 4336 概率DP 状压
    HDU 4089 && UVa 1498 Activation 带环的概率DP
    SGU 149 树形DP Computer Network
    暑假集训刷题记录
  • 原文地址:https://www.cnblogs.com/rsapaper/p/9919511.html
Copyright © 2011-2022 走看看