DEV Community

Alex
Alex

Posted on

.NET Learning Notes: YARP

A reverse proxy is a server that sits in fronts of one or more backend servers and handles requests from clients on behalf of those servers.

A reverse proxy provides several benefits:

  • Routing
  • Load balancing
  • Scalability: By distributing traffic across multiple serves, a reverse proxy helps scale apps to handle more users and higher loads.
  • SSL/TLS Termination
  • Incoming URLs can be transformed before forwarding to the backend. Internal service endpoints can change without affecting external URLs.
  • Security: Internal service endpoints can be hidden from external exposure.
  • Caching # YARP ## 1. Load Balancing Load balancing policies are registered in the DI container via the AddLoadBalancingPolicies() method, which is automatically called by AddReverseProxy(). The middleware is added with UseLoadBalancing, which is included by default in the parameterless MapReverseProxy method. ### Cluster Configuration The algorithm used to determine the destination can be configured by setting the LoadBalancingPolicy. If no policy is specified, PowerOfTwoChoices will be used. Built-in policies:
  • FirstAlphabetical
  • Random
  • PowerOfTwoChoices (default)
  • RoundRobin
  • LeastRequests
"ReverseProxy": {
  "Clusters": {
    "cluster1": {
      "LoadBalancingPolicy": "RoundRobin",
      "Destinations": {
        "cluster1/destination1": {
          "Address": "https://localhost:10000/"
        },
        "cluster1/destination2": {
          "Address": "https://localhost:10010/"
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

2. Session Affinity

Session affinity is a mechanism to bind a causally related request sequence to the destination that handled the first request when the load is balanced among several destinations.

What is an Affinity Key

In YARP, an Affinity Key is simply the identifier that ties a client's subsequent requests to the same backend destination.

  • The key itself is just a container name.
  • The value stored inside that key is generated dynamically by YARP at runtime and is different for each client or session.
  • This value encodes the target destination ID - or sometimes a group of destinations - so that the proxy knows where to route the next request. ### Affinity failure policy
  • Redistribute (default)- tries to establish a new affinity to one of available healthy destinations by skipping the affinity lookup step and passing all healthy destination to the load balancer the same way it is done for a request without any affinity.
  • Return503Error - send a 503 response back to the client and request processing is terminated. ## 3. Destination health checks ### Active health checks YARP can proactively monitor destination health by sending periodic probing requests to designated health endpoints and analyzing responses.
"Clusters": {
  "cluster1": {
    "HealthCheck": {
      "Active": {
        "Enabled": "true",
        "Interval": "00:00:10",
        "Timeout": "00:00:10",
        "Policy": "ConsecutiveFailures",
        "Path": "/api/health",
        "Query": "?foo=bar"
      }
    },
    "Metadata": {
      "ConsecutiveFailuresHealthPolicy.Threshold": "3"
    },
    "Destinations": {
      "cluster1/destination1": {
        "Address": "https://localhost:10000/"
      },
      "cluster1/destination2": {
        "Address": "http://localhost:10010/",
        "Health": "http://localhost:10020/"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Passive health checks

YARP can passively watch for successes and failures in client request proxying to reactively evaluate destination health states.

"Clusters": {
  "cluster1": {
    "HealthCheck": {
      "Passive": {
        "Enabled": "true",
        "Policy": "TransportFailureRate",
        "ReactivationPeriod": "00:02:00"
      }
    },
    "Metadata": {
      "TransportFailureRateHealthPolicy.RateLimit": "0.5"
    },
    "Destinations": {
      "cluster1/destination1": {
        "Address": "https://localhost:10000/"
      },
      "cluster1/destination2": {
        "Address": "http://localhost:10010/"
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

When a destination gets marked as unhealthy, it stops receiving new requests until it gets reactivated after a configured period.

4. Rate Limiting

The reverse proxy can be used to rate-limit requests before they are proxied to the destination servers. This can reduce load on the destination servers, add a layer of protection, and ensure consistent policies are implemented across your applications.

Global Limiter

globalLimiter is an illustration here, we need to implement it by ourself.

services.AddRateLimiter(options => options.GlobalLimiter = globalLimiter);
Enter fullscreen mode Exit fullscreen mode

Route Limiter

Rate limiter policies can be specified per route.

{
  "ReverseProxy": {
    "Routes": {
      "route1" : {
        "ClusterId": "cluster1",
        "RateLimiterPolicy": "customPolicy",
        "Match": {
          "Hosts": [ "localhost" ]
        }
      }
    },
    "Clusters": {
      "cluster1": {
        "Destinations": {
          "cluster1/destination1": {
            "Address": "https://localhost:10001/"
          }
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

RateLimiter policies can be configured in services as follows:

services.AddRateLimiter(options =>
{
    options.AddFixedWindowLimiter("customPolicy", opt =>
    {
        opt.PermitLimit = 4;
        opt.Window = TimeSpan.FromSeconds(12);
        opt.QueueProcessingOrder = QueueProcessingOrder.OldestFirst;
        opt.QueueLimit = 2;
    });
});
Enter fullscreen mode Exit fullscreen mode

Then add the RateLimiter middleware:

app.UseRateLimiter();

app.MapReverseProxy();
Enter fullscreen mode Exit fullscreen mode

Disable Rate Limiting

Specifying the value disable in a route's RateLimiterPolicy parameter means the rate limiter middleware will not apply any policies to this route, even the default policy.

Top comments (0)