首页 > 系统相关 >微软用Yarp取代了`Nginx`吞吐量提升了百分之八十!

微软用Yarp取代了`Nginx`吞吐量提升了百分之八十!

时间:2024-01-16 10:26:17浏览次数:31  
标签:content 百分之八十 builder Yarp Nginx new var using

先来看一张图:

Azure应用服务用YARP取代了Nginx,获得了80%以上的吞吐量。他们每天处理160B多个请求(1.9 m RPS)。这是微软的一项了不起的技术创新。

首先我们来介绍一下什么是Yarp

Yarp是什么?

YARP(Yet Another Reverse Proxy)是一个开源的、高性能的反向代理库,由Microsoft开发,使用C#语言编写。它旨在作为.NET平台上构建反向代理服务器的基础。YARP主要针对.NET 5及以上版本,允许开发者在.NET应用程序中轻松地实现反向代理的功能。

YARP的主要特点和功能:

  1. 模块化和可扩展性: YARP设计成高度模块化的,这意味着可以根据需要替换或扩展内部组件,如HTTP请求路由、负载均衡、健康检查等。
  2. 性能: YARP针对高性能进行了优化,利用了.NET的异步编程模型和高效的IO操作,以处理大量并发连接。
  3. 配置驱动: YARP的行为可以通过配置来控制,支持从文件、数据库或其他来源动态加载配置。
  4. 路由: 可以基于各种参数(如路径、头部、查询参数)配置请求路由规则。
  5. 负载均衡: 内置多种负载均衡策略,如轮询、最少连接、随机选择等,并且可以自定义负载均衡策略。
  6. 健康检查: 支持后端服务的健康检查,以确保请求只会被转发到健康的后端服务实例。
  7. 转换器: 允许对请求和响应进行转换,如修改头部、路径或查询参数。
  8. 会话亲和性: 支持会话亲和性(Session Affinity),确保来自同一客户端的请求被发送到相同的后端服务实例。

使用YARP的一些场景:

  • 反向代理: 在客户端和后端服务之间提供一个中间层,用于请求转发和负载均衡。
  • API网关: 作为微服务架构中的API网关,提供路由、鉴权、监控等功能。
  • 边缘服务: 在应用程序和外部世界之间提供安全层,处理SSL终止、请求限制等任务。

Yarp简单的使用

创建一个WebApi的项目

安装Nuget

<ItemGroup>
	<PackageReference Include="Yarp.ReverseProxy" Version="2.0.0" />
</ItemGroup>

打开appsettings.json

{
 "Logging": {
   "LogLevel": {
     "Default": "Information",
     "Microsoft": "Warning",
     "Microsoft.Hosting.Lifetime": "Information"
   }
 },
 "AllowedHosts": "*",
 "ReverseProxy": {
   "Routes": {
     "route1" : {
       "ClusterId": "cluster1",
       "Match": {
         "Path": "{**catch-all}"
       }
     }
   },
   "Clusters": {
     "cluster1": {
       "Destinations": {
         "destination1": {
           "Address": "https://cn.bing.com/"
         }
       }
     }
   }
 }
}

打开Program.cs

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddReverseProxy()
    .LoadFromConfig(builder.Configuration.GetSection("ReverseProxy"));
var app = builder.Build();
app.MapReverseProxy();
app.Run();

然后启动项目,访问我们的api就会被代理转发到bing

Yarp工具代理使用

下面我们在提供一个在中间件使用yarp的方式

我们需要用到IHttpForwarder

先修改Program.cs 在这里我们注入了HttpForwarder,然后提供一个Run中间件,在中间件中手动指定了端点的地址https://cn.bing.com/ 然后我们启动一下项目。

using Yarp.ReverseProxy.Forwarder;

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpForwarder(); // 注入IHttpForwarder 
var app = builder.Build();

var httpMessage = new HttpMessageInvoker(new HttpClientHandler());

app.Run((async context =>
{
    var httpForwarder = context.RequestServices.GetRequiredService<IHttpForwarder>();
    var destinationPrefix = "https://cn.bing.com/";

    await httpForwarder.SendAsync(context, destinationPrefix, httpMessage);
}));

app.Run();

也是一样会被代理过去,但是于简单使用不一样的是我们是在代码层面控制代理的。

使用yarp修改Bing的响应内容

我们继续基于上面的代理使用进行修改bing的相应内容!

打开Program.cs

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHttpForwarder(); // 注入IHttpForwarder 
var app = builder.Build();

var httpMessage = new HttpMessageInvoker(new HttpClientHandler()
{
    // 忽略https错误
    ServerCertificateCustomValidationCallback = (_, _, _, _) => true,
    AllowAutoRedirect = false,
    AutomaticDecompression = DecompressionMethods.GZip,
    UseCookies = false,
    UseProxy = false,
    UseDefaultCredentials = true,
});
var destinationPrefix = "https://cn.bing.com/";

var bingTransformer = new BingTransformer();

app.Run((async context =>
{
    var httpForwarder = context.RequestServices.GetRequiredService<IHttpForwarder>();
    await httpForwarder.SendAsync(context, destinationPrefix, httpMessage, new ForwarderRequestConfig(),
        bingTransformer);
}));

app.Run();

创建BingTransformer.cs

public class BingTransformer : HttpTransformer
{
    public override async ValueTask TransformRequestAsync(HttpContext httpContext, HttpRequestMessage proxyRequest,
        string destinationPrefix,
        CancellationToken cancellationToken)
    {
        var uri = RequestUtilities.MakeDestinationAddress(destinationPrefix, httpContext.Request.Path,
            httpContext.Request.QueryString);
        proxyRequest.RequestUri = uri;
        proxyRequest.Headers.Host = uri.Host;
        await base.TransformRequestAsync(httpContext, proxyRequest, destinationPrefix, cancellationToken);
    }

    public override async ValueTask<bool> TransformResponseAsync(HttpContext httpContext,
        HttpResponseMessage? proxyResponse,
        CancellationToken cancellationToken)
    {
        await base.TransformResponseAsync(httpContext, proxyResponse, cancellationToken);

        if (httpContext.Request.Method == "GET" &&
            httpContext.Response.Headers["Content-Type"].Any(x => x.StartsWith("text/html")))
        {
            var encoding = proxyResponse.Content.Headers.FirstOrDefault(x => x.Key == "Content-Encoding").Value;
            if (encoding?.FirstOrDefault() == "gzip")
            {
                var content = proxyResponse?.Content.ReadAsByteArrayAsync(cancellationToken).Result;
                if (content != null)
                {
                    var result = Encoding.UTF8.GetString(GZipDecompressByte(content));
                    result = result.Replace("国内版", "Token Bing 搜索 - 国内版");
                    proxyResponse.Content = new StringContent(GZipDecompressString(result));
                }
            }
            else if (encoding.FirstOrDefault() == "br")
            {
                var content = proxyResponse?.Content.ReadAsByteArrayAsync(cancellationToken).Result;
                if (content != null)
                {
                    var result = Encoding.UTF8.GetString(BrDecompress(content));
                    result = result.Replace("国内版", "Token Bing 搜索 - 国内版");
                    proxyResponse.Content = new ByteArrayContent(BrCompress(result));
                }
            }
            else
            {
                var content = proxyResponse?.Content.ReadAsStringAsync(cancellationToken).Result;
                if (content != null)
                {
                    content = content.Replace("国内版", "Token Bing 搜索 - 国内版");
                    proxyResponse.Content = new StringContent(content);
                }
            }
        }

        return true;
    }

    /// <summary>
    /// 解压GZip
    /// </summary>
    /// <param name="bytes"></param>
    /// <returns></returns>
    public static byte[] GZipDecompressByte(byte[] bytes)
    {
        using var targetStream = new MemoryStream();
        using var compressStream = new MemoryStream(bytes);
        using var zipStream = new GZipStream(compressStream, CompressionMode.Decompress);
        using (var decompressionStream = new GZipStream(compressStream, CompressionMode.Decompress))
        {
            decompressionStream.CopyTo(targetStream);
        }

        return targetStream.ToArray();
    }

    /// <summary>
    /// 解压GZip
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    public static string GZipDecompressString(string str)
    {
        using var compressStream = new MemoryStream(Encoding.UTF8.GetBytes(str));
        using var zipStream = new GZipStream(compressStream, CompressionMode.Decompress);
        using var resultStream = new StreamReader(new MemoryStream(compressStream.ToArray()));
        return resultStream.ReadToEnd();
    }

    /// <summary>
    /// Br压缩
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public static byte[] BrCompress(string str)
    {
        using var outputStream = new MemoryStream();
        using (var compressionStream = new BrotliStream(outputStream, CompressionMode.Compress))
        {
            compressionStream.Write(Encoding.UTF8.GetBytes(str));
        }

        return outputStream.ToArray();
    }

    /// <summary>
    /// Br解压
    /// </summary>
    /// <param name="input"></param>
    /// <returns></returns>
    public static byte[] BrDecompress(byte[] input)
    {
        using (var inputStream = new MemoryStream(input))
        using (var outputStream = new MemoryStream())
        using (var decompressionStream = new BrotliStream(inputStream, CompressionMode.Decompress))
        {
            decompressionStream.CopyTo(outputStream);
            return outputStream.ToArray();
        }
    }
}

得到的效果我们将国内版修改成了Token Bing 搜索 - 国内版

Yarp AOT尝试

下面我们将Yarp进行AOT尝试,首先打开我们的项目,添加以下参数

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <InvariantGlobalization>true</InvariantGlobalization>
    <PublishAot>true</PublishAot>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Yarp.ReverseProxy" Version="2.0.0" />
  </ItemGroup>
</Project>

AOT以后的大小15MB

测试转发并无问题

优化AOT大小,添加以下参数

<Project Sdk="Microsoft.NET.Sdk.Web">

  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <InvariantGlobalization>true</InvariantGlobalization>
    <PublishAot>true</PublishAot>

    <StackTraceSupport>false</StackTraceSupport>
    <OptimizationPreference>Size</OptimizationPreference>
    <PublishTrimmed>true</PublishTrimmed>
    <BlazorEnableTimeZoneSupport>false</BlazorEnableTimeZoneSupport>
    <EventSourceSupport>false</EventSourceSupport>
    <HttpActivityPropagationSupport>false</HttpActivityPropagationSupport>
    <EnableUnsafeBinaryFormatterSerialization>false</EnableUnsafeBinaryFormatterSerialization>
    <MetadataUpdaterSupport>false</MetadataUpdaterSupport>
    <UseNativeHttpHandler>true</UseNativeHttpHandler>
    <TrimMode>link</TrimMode>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Yarp.ReverseProxy" Version="2.0.0" />
  </ItemGroup>
</Project>

减少2MB左右,并且正常运行代理

Yarp相关资料

技术交流群:737776595

官方文档:https://microsoft.github.io/reverse-proxy/articles/getting-started.html

来着token的分享

 

2024-01-16 10:09:15【出处】:https://www.cnblogs.com/hejiale010426/p/17954360

=======================================================================================

标签:content,百分之八十,builder,Yarp,Nginx,new,var,using
From: https://www.cnblogs.com/mq0036/p/17967028

相关文章

  • nginx代理,http下载文件到1G就终止的问题
    我们使用了nginx作为网关,项目中发现再互联网上http下载超过1G的文件就自动终止。但是在局域网中下载正常。查看NGINX的官方文档:http://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_buffering从NGINX的缓存配置中发现了一个参数:proxy_max_temp_file_size 看到......
  • 13、nginx自动列出目录
    1,配置userroot;worker_processes4;events{useepoll;worker_connections1024;}http{server{listen80;server_name127.0.0.1;location/{#指定要展示的目录root/root/nginx......
  • 12、nginx日志配置
    1.nginx日志指令log_format:用于设置日志格式access_log:用于指定日志文件存放路径、格式、缓存大小可设置在http、server块中2.log_format2.1log_format语法log_formatnameformat[format...]name表示定义的格式名称format表示定义的格式样式。log_forma......
  • nginx配置虚拟主机机
    1.配置文件#设置进程数worker_processes4;#设置启动用户,一般情况下设置为当前用户,要不然会出现权限不足userroot;events{worker_connections1024;}http{#设置虚拟主机1server{listen8001;server_name172.16.122.177;......
  • 使用HTTP/2在Linux上的Nginx服务器进行优化
    随着互联网的发展,HTTP/2协议逐渐成为主流。与传统的HTTP/1.1相比,HTTP/2提供了更高的传输效率和更好的安全性。在Linux上使用Nginx服务器进行优化,我们可以充分利用HTTP/2的优势,提高网站的性能和用户体验。安装Nginx并启用HTTP/2首先,确保你的Nginx服务器已经安装并正常运行。要启用H......
  • 在Linux上使用PHP-FPM与Nginx实现高效的HTTP处理
    当谈到高效的HTTP处理时,PHP-FPM(FastCGI进程管理器)与Nginx的结合是许多web开发者的首选。这种组合提供了出色的性能、可扩展性和稳定性,尤其适用于高流量的网站和应用程序。1.为什么选择PHP-FPM与Nginx?· 性能优化:PHP-FPM通过进程管理和缓存机制,显著提高了PHP脚本的执行效率。· ......
  • [转帖]Nginx access log 按日期保存记录
    https://cloud.tencent.com/developer/article/1958304 $time_iso8601  生成格式:2021-09-18T15:16:35+08:00$time_local     生成格式:18/Sep/2021:15:12:13+0800网络流传的nginxaccesslog分割都是写shell脚本然后做定时任务来分割日志,操作中自......
  • NGINX 路由配置与参数详解(https配置、跨域配置、socket配置)
    目录一、概述二、https配置1)获取SSL证书2)安装SSL证书3)Nginx配置修改4)重新加载Nginx配置三、nginx跨域配置四、nginxsocket配置五、NGINX路由配置1)基本的URI匹配2)nginx中斜杠(/)1、location以斜杠结尾,proxy_pass不以斜杠结尾2、location不以斜杠结尾,proxy_pass......
  • 解决nginx http 429
    当Nginx作为反向代理服务器收到HTTP429TooManyRequests响应时,这通常意味着后端服务由于请求速率过高而拒绝了更多的请求。要解决这个问题,可以从以下几个方面入手:调整客户端请求频率:如果你是客户端应用的开发者,可以通过限制应用程序发出请求的速度来避免触发后端服务的限流策略......
  • docker安装nginx
    1、查找镜像源dockersearchnginx2、拉取img镜像dockerpullnginx:latest 3、创建Nginx配置文件启动前需要先创建Nginx外部挂载的配置文件(/home/nginx/conf/nginx.conf)之所以要先创建,是因为Nginx本身容器只存在/etc/nginx目录,本身就不创建nginx.conf文件当服务......