目录

Welcome to YARP - 1.认识YARP并搭建反向代理服务

Welcome to YARP - 2.配置功能

Welcome to YARP - 3.负载均衡

Welcome to YARP - 4.限流

Welcome to YARP - 5.身份验证和授权

Welcome to YARP - 6.压缩、缓存

Welcome to YARP - 7.健康检查

Welcome to YARP - 8.分布式跟踪

介绍

网关的 缓存压缩是常见的性能优化手段 ,用于提高系统的响应速度和降低网络传输的开销。

YARP 的 缓存压缩 其实也是 .NET 本身的功能。只需要配置 .NET 本身的缓存和压缩功能即可。

缓存

缓存的主要目的是优化性能、提高效率,减少对后端服务的负担。 我们可以对

频繁请求的静态数据或不经常更改的数据 进行 API 缓存,从而降低对后端服务的请求次数,提高响应速度,减轻后端服务的负载。

也可以对 静态资源 缓存 如:css、js、图像等,从而 加速页面加载速度,减轻服务器压力,提高用户体验。 等等。

基于 HTTP 的响应缓存

用于缓存的主 HTTP 标头是 Cache-Control,它用于指定缓存指令。 当请求从客户端到达服务器以及响应从服务器返回客户端时,这些指令控制缓存行为。 请求和响应在代理服务器之间移动,并且代理服务器还必须符合 HTTP 1.1 缓存规范。

Cache-Control 通用消息头字段,被用于在 http 请求和响应中,通过指定指令来实现缓存机制。缓存指令是单向的,这意味着在请求中设置的指令,不一定被包含在响应中。

要使用缓存,请求头中必须携带 Cache-Control 标头。同时响应头中也要做相应的设置。

下表中显示了常用 Cache-Control 指令

指令 操作
public 缓存可以存储响应。
private 响应不得由共享缓存存储。 专用缓存可以存储和重用响应。
max-age 客户端不接受期限大于指定秒数的响应。 示例:max-age=60(60 秒),max-age=2592000(1 个月)
no-cache 请求时:缓存不能使用存储的响应来满足请求。 源服务器重新生成客户端的响应,中间件更新其缓存中存储的响应。 响应时:响应不得用于未经源服务器验证的后续请求。
no-store 请求时:缓存不得存储请求。 响应时:缓存不得存储任何部分的响应。

相应的我们也要添加响应缓存中间件:

若要测试响应缓存,请使用 Fiddler、Postman 或其他可以显式设置请求标头的工具。显式设置上述的请求标头。

配置中间件

在 中 Program.cs ,将响应缓存中间件服务 AddResponseCaching 添加到服务集合中,并将应用配置为将中间件与 UseResponseCaching 扩展方法一起使用。 UseResponseCaching 将中间件添加到请求处理管道中:

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddReverseProxy()//添加ReverseProxy相关服务到DI
.LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));//从配置文件中加载ReverseProxy的设置 builder.Services.AddResponseCaching(options =>
{
options.UseCaseSensitivePaths = false; //确定是否将响应缓存在区分大小写的路径上。
options.SizeLimit = options.SizeLimit * 10; // 响应缓存中间件的大小限制(以字节为单位) 1G
}); var app = builder.Build(); if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
} // 使用 CORS 中间件时,必须在 UseResponseCaching 之前调用 UseCors。
// app.UseCors();
app.UseRouting(); // 拦截请求并判断 请求头中是否包含 CacheControl 标头,如果没有则加上缓存标头
app.Use(async (context, next) =>
{
var header = context.Request.Headers;
var cacheControl = header.CacheControl;
if (!string.IsNullOrEmpty(header.CacheControl))
{
header.CacheControl = new Microsoft.Extensions.Primitives.StringValues("max-age");
} await next(context);
});
app.UseResponseCaching();
app.Use(async (context, next) =>
{
context.Response.GetTypedHeaders().CacheControl =
new Microsoft.Net.Http.Headers.CacheControlHeaderValue()
{
Public = true,
MaxAge = TimeSpan.FromSeconds(10)
}; context.Response.Headers[Microsoft.Net.Http.Headers.HeaderNames.Vary] = new string[] { "Accept-Encoding" }; await next(context);
});
app.MapReverseProxy(); app.MapGet("/", () => DateTime.Now.ToLongTimeString()); app.Run();

以上示例中:

  • Cache-Control:缓存可缓存响应长达10秒。
  • Vary:将中间件配置为仅当后续请求的 Accept-Encoding 标头与原始请求头匹配时才提供缓存的响应。

app.Use(async (context, next) =>

{

var header = context.Request.Headers;

var cacheControl = header.CacheControl;

if (!string.IsNullOrEmpty(header.CacheControl))

{

header.CacheControl = new Microsoft.Extensions.Primitives.StringValues("max-age");

}

await next(context);

});

可以看到我们先设置了 请求头的 缓存标头,如果 没有此 设置,几乎所有浏览器(标头值)都会发送 CacheControl:no-cache 或其他值,强制执行非缓存页面请求,这会导致 ResponseCachingMiddleware 实现忽略此请求(忽略缓存)并将其传递到服务器以检索数据。 如果你用 postman 或者 fiddle则可以主动这只CacheControl标头值为上述说的那几种。

上述示例中我们先 添加了 YARP 服务,然后添加了 AddResponseCaching 响应的缓存服务,然后拦截了请求并设置缓存标头,再开启了 UseResponseCaching() 响应缓存中间件。接下来设置了 [响应头的标头值]( ASP.NET Core 中的响应缓存中间件 | Microsoft Learn ),最后开启了 代理 中间件。源码已上传GitHub.

压缩

网络带宽是一种有限资源。 减小响应大小通常可显著提高应用的响应速度。 减小有效负载大小的一种方式是压缩应用的响应。 但是 YARP 默认是禁用解压缩的,因为它会增加 CPU 开销。

什么时候使用 响应压缩 中间件?

在 IIS、Apache 或 Nginx 中使用基于服务器的响应压缩技术。

而 HTTP.sys 服务器和 Kestrel 服务器当前不提供内置压缩支持,这时候就需要使用响应压缩中间件了。

我们使用 YARP 的直接转发来 演示一下 压缩功能,当然压缩是 .NET 本身自带的功能,你也可以通过添加压缩中间件来开启响应压缩。

代码示例:

using System.Diagnostics;
using System.Net;
using Yarp.ReverseProxy.Forwarder;
using Yarp.ReverseProxy.Transforms; var builder = WebApplication.CreateBuilder(args); builder.Services.AddHttpForwarder(); // Add services to the container. var app = builder.Build(); // Configure our own HttpMessageInvoker for outbound calls for proxy operations
var httpClient = new HttpMessageInvoker(new SocketsHttpHandler()
{
UseProxy = false,
AllowAutoRedirect = false,
AutomaticDecompression = DecompressionMethods.GZip, // 设置响应压缩方式
UseCookies = false,
ActivityHeadersPropagator = new ReverseProxyPropagator(DistributedContextPropagator.Current),
ConnectTimeout = TimeSpan.FromSeconds(15),
}); // Setup our own request transform class
var transformer = new CustomTransformer(); // or HttpTransformer.Default;
var requestConfig = new ForwarderRequestConfig { ActivityTimeout = TimeSpan.FromSeconds(100) }; app.UseRouting(); // Configure the HTTP request pipeline. app.MapForwarder("/{**catch-all}", "http://localhost:5047", requestConfig, transformer, httpClient); app.Run(); /// <summary>
/// 自定义请求转换
/// </summary>
class CustomTransformer : HttpTransformer
{
///<summary>
/// A callback that is invoked prior to sending the proxied request. All HttpRequestMessage
/// fields are initialized except RequestUri, which will be initialized after the
/// callback if no value is provided. The string parameter represents the destination
/// URI prefix that should be used when constructing the RequestUri. The headers
/// are copied by the base implementation, excluding some protocol headers like HTTP/2
/// pseudo headers (":authority").
///</summary>
///<param name="httpContext">传入请求</param>
///<param name="proxyRequest">传出的代理请求</param>
///<param name="destinationPrefix">所选目标服务器的uri前缀,可用于创建RequestUri</param>
public override async ValueTask TransformRequestAsync(HttpContext httpContext, HttpRequestMessage proxyRequest, string destinationPrefix, CancellationToken cancellationToken)
{
// 转发所有头部信息
await base.TransformRequestAsync(httpContext, proxyRequest, destinationPrefix, cancellationToken);
// 自定义查询query 值
var queryContext = new QueryTransformContext(httpContext.Request);
queryContext.Collection.Remove("param1");
queryContext.Collection["s"] = "xx2";
// 分配自定义 URI。在此处连接时请注意额外的斜杠。RequestUtilities.MakeDestinationAddress 是一个安全的默认值。
proxyRequest.RequestUri = RequestUtilities.MakeDestinationAddress("http://localhost:5047", httpContext.Request.Path, queryContext.QueryString);
// 禁止原始请求标头,使用目标 Uri 中的标头
proxyRequest.Headers.Host = null;
}
}

上述示例中,我们使用了 YARP 的直接转发模式,不需要添加 YARP 服务和中间件,但是要添加 这个东西 AddHttpForwarder,然后配置 自定义请求转换 类。并开启 压缩模式为 GZip。

如果想看效果记得使用fiddle 抓取请求的返回值查看原始请求,因为postman和浏览器客户端 都会默认对常用的压缩格式的数据进行解压缩。

如果服务器本身支持压缩,请使用 基于服务器的压缩技术。而 HTTP.sys 服务器和 Kestrel 服务器 是不支持压缩技术的,所以这时候才考虑使用 压缩中间件。

总结

本章我们介绍了 YARP 的缓存和压缩功能,其实也都是 .NET 自身的功能,如果了解使用过 .NET的 缓存 和 压缩 中间件很容易就能理解。本章示例代码已上传GitHub,建议把代码down下来自己实验一下,再去配合理解。

有什么问题欢迎留言交流。

下篇文章我们继续介绍 YARP 的健康检查功能。

Welcome to YARP - 5.压缩、缓存的更多相关文章

  1. nginx压缩,缓存

    https://www.darrenfang.com/2015/01/setting-up-http-cache-and-gzip-with-nginx/ https://www.linuxdashe ...

  2. Tomcat系列(9)——Tomcat 6方面调优(内存,线程,IO,压缩,缓存,集群)

    核心部分 内存 线程 IO 压缩 缓存 集群 一.JVM内存优化 Tomcat内存优化,包括内存大小,垃圾回收策略. Windows 下的catalina.bat,Linux 下的catalina.s ...

  3. .net字符串Gzip压缩和base64string转换:

    class Program { static void Main(string[] args) { //要压缩的字符串 string data = "13800138000,验证码:1234 ...

  4. spring ehcache 页面、对象缓存

    一.Ehcache基本用法 CacheManager cacheManager = CacheManager.create(); // 或者 cacheManager = CacheManager.g ...

  5. Ehcache 整合Spring 使用页面、对象缓存

    Ehcache 整合Spring 使用页面.对象缓存 Ehcache在很多项目中都出现过,用法也比较简单.一 般的加些配置就可以了,而且Ehcache可以对页面.对象.数据进行缓存,同时支持集群/分布 ...

  6. (转)Ehcache 整合Spring 使用页面、对象缓存

    Ehcache在很多项目中都出现过,用法也比较简单.一般的加些配置就可以了,而且Ehcache可以对页面.对象.数据进行缓存,同时支持集群/分布式缓存.如果整合Spring.Hibernate也非常的 ...

  7. 缓存插件 EHCache 页面缓存CachingFilter

    Ehcache基本用法 CacheManager cacheManager = CacheManager.create(); // 或者 cacheManager = CacheManager.get ...

  8. Web服务器处理HTTP压缩之gzip、deflate压缩

    现如今在处理http请求的时候,由于请求的资源较多,如果不启用压缩的话,那么页面请求的流量将会非常大.启用gzip压缩,在一定程度上会大大的提高页面性能.   目录 一.什么是gzip 二.什么是de ...

  9. apache启用gzip压缩方法--转载自http://www.cnblogs.com/linzhenjie/archive/2013/03/05/2943635.html

    一.gzip介绍 Gzip是一种流行的文件压缩算法,现在的应用十分广泛,尤其是在Linux平台.当应用Gzip压缩到一个纯文本文件时,效果是非常明显的,大约可以减少70%以上的文件大小.这取决于文件中 ...

  10. Ehcache 整合Spring 使用页面、对象缓存(转载)

    Ehcache在很多项目中都出现过,用法也比较简单.一般的加些配置就可以了,而且Ehcache可以对页面.对象.数据进行缓存,同时支持集群/分布式缓存.如果整合Spring.Hibernate也非常的 ...

随机推荐

  1. 2021-8-5 Microsoft文档学习笔记(C#)

    以下列表概述了类可以包含的成员类型. 常量:与类相关联的常量值 字段:与类关联的变量 方法:类可执行的操作 属性:与读取和写入类的已命名属性相关联的操作 索引器:与将类实例编入索引(像处理数组一样)相 ...

  2. go项目实现在配置文件实现配置项统一管理

    转载请注明出处: go项目中实现配置项统一管理,实现逻辑:将 配置项整理为一个json的数据结构,并保存到go.conf文件中,然后在go项目启动main方法中加载 go.conf 文件,读取go.c ...

  3. VScode 中golang 单元测试,解决单元测试超时timeout30s

    目的:单元测试的主要目的是验证代码的每个单元(函数.方法)是否按照预期工作. 提示:解决单元测试超时30s的问题在序号4 1 准备以_test.go结尾文件和导入testing包 在命名文件时需要让文 ...

  4. 使用 Go 语言实现二叉搜索树

    原文链接: 使用 Go 语言实现二叉搜索树 二叉树是一种常见并且非常重要的数据结构,在很多项目中都能看到二叉树的身影. 它有很多变种,比如红黑树,常被用作 std::map 和 std::set 的底 ...

  5. 批量获取FreeSWITCH所有分机号及其密码

    前言 有次项目上需要获取所有FreeSWITCH注册分机的分机号和密码,就用python写了个小脚本来获取. 可以先把freeswitch/conf/directory/default/目录下的所有x ...

  6. salesforce零基础学习(一百三十)Report 学习进阶篇

    本篇参考: https://help.salesforce.com/s/articleView?id=sf.reports_summary_functions_about.htm&type=5 ...

  7. centos7关闭防火墙后只有22端口可以telnet的解决方法

    1.问题描述 防火墙已经关闭 22端口可以telnet 其他端口无法telnet 2.解决方法 注意:下列命令要用root账号/权限执行 2.1.开启防火墙 systemctl start firew ...

  8. [Python] 今天开始学习Python3了, 纪念一下

    #! /usr/bin/env python3 import time print("你好, 请告诉我你的名字.") name = input("名前: ") ...

  9. react移动端上拉加载更多组件

    在开发移动端react项目中,遇到了上拉加载更多数据的分页功能,自己封装了一个组件,供大家参考,写的不好还请多多指教! import React, {Component} from 'react'; ...

  10. vivo数据中心网络链路质量监测的探索实践

    作者:vivo 互联网服务器团队- Wang Shimin 网络质量监测中心是一个用于数据中心网络延迟测量和分析的大型系统.通过部署在服务器上的Agent发起5次ICMP Ping以获取端到端之间的网 ...