asp.net菜单栏伸缩_使用ASP.NET Core构建水平可伸缩有状态应用程序

asp.net菜单栏伸缩

In the tech world new technologies come and go. With technologies like Docker Engine and Kubernetes, scaling out of applications became easier than ever. This unfortunately doesn’t mean that applications are horizontal scalable out of the box. In this article the problems will be explained and solved with the .NET landscape in mind.

在技​​术世界中,新技术不断出现。 借助Docker EngineKubernetes之类的技术,扩展应用程序比以往任何时候都更加容易。 不幸的是,这并不意味着应用程序是水平可扩展的。 在本文中,将牢记.NET格局来解释和解决问题。

In this post we will first define the difference between horizontal and vertical scaling, better known as Scaling out and Scaling up. We continue with learning the differences between a stateless and stateful application, followed by solving the problems for specific protocols and technologies that arise when scaling out a stateful ASP.NET Core application.

在本文中,我们将首先定义水平缩放和垂直缩放之间的差异,即所谓的向外扩展和向上扩展。 我们将继续学习无状态应用程序和有状态应用程序之间的差异,然后解决在扩展有状态ASP.NET Core应用程序时出现的特定协议和技术的问题。

向上扩展与向外扩展 (Scaling up vs Scaling out)

When researching the principle of scaling an application, it is a must to understand what scaling is. Scaling an application is growing one or multiple infrastructure components (compute, storage, networking) larger in such a way that applications can serve more requests at the same time. This can be done in two ways.

在研究扩展应用程序的原理时,必须了解什么是扩展。 扩展应用程序使一个或多个基础结构组件(计算,存储,网络)变得更大,从而使应用程序可以同时服务于更多请求。 这可以通过两种方式完成。

Image for post
Scaling up
扩大

By scaling up, as well known as vertical scaling, existing components become bigger. In terms of a server this would mean to add more memory (Compute) or disk space (storage) to be able to run a heavier application on the same physical machine.

通过按比例放大 (即垂直缩放),现有组件会变得更大。 对于服务器而言,这意味着要添加更多内存(计算)或磁盘空间(存储),以便能够在同一台物理计算机上运行更重的应用程序。

Image for post
Scaling out
向外扩展

Another way of scaling is by scaling out, as well known as horizontal scaling. Instead of making existing components larger, more components are added in parallel. In terms of compute this would mean to add an extra server with its own dedicated memory and disk space to serve an extra instance of an application.

缩放的另一种方法是向外扩展,即水平缩放。 与其增加现有组件的大小,不如并行添加更多的组件。 在计算方面,这意味着要添加额外的服务器,该服务器具有自己的专用内存和磁盘空间来为应用程序的额外实例提供服务。

When scaling up, a machine or a web application can only handle that limited amount of extra resources. The OS could for example only a certain amount of memory or disk space. Or all CPU power is already being utilized and can’t be expanded.

向上扩展时,机器或Web应用程序只能处理有限数量的额外资源。 例如,操作系统只能有一定数量的内存或磁盘空间。 或所有CPU功能已被利用且无法扩展。

At that moment scaling out will inevitable. With scaling out, new problems are introduced since multiple instances will be responsible for handling concurrent requests. Can these requests for instance work with multiple instances of the application?

在那一刻,向外扩展是不可避免的。 随着横向扩展,由于多个实例将负责处理并发请求,因此引入了新问题。 这些请求是否可以与应用程序的多个实例一起使用?

无状态与有状态 (Stateless vs stateful)

When it’s desired to scale out an application, one of the hurdles that needs to be taken is determining if the application to scale is stateful or stateless.

当需要扩展应用程序时,需要考虑的障碍之一就是确定要扩展的应用程序是有状态的还是无状态的。

Imagine this case, a back office application made with .NET Core MVC, has grown that much in load that the development team desire to scale out the application to multiple instances. The developers used server-side sessions to share information between requests.

想象一下这种情况,使用.NET Core MVC制作的后台应用程序已经增加了很多负载,开发团队希望将其扩展到多个实例。 开发人员使用服务器端会话在请求之间共享信息。

The team as well used cookies to prevent Cross-Site Request Forgery (CSRF) attacks. The cookies are generated along side every request and contain information to validate the requests are sent from the application during the next request. The cookies are encrypted with protection keys which are generated on startup and stored in-memory. When scaling out the application to multiple instances and routing the requests over the multiple instances, there is need to share these keys.

该团队还使用cookie来防止跨站请求伪造(CSRF)攻击 。 Cookie随每个请求一起生成,并包含用于验证在下一个请求期间从应用程序发送请求的信息。 Cookies使用启动时生成并存储在内存中的保护密钥进行加密。 当将应用程序扩展到多个实例并在多个实例上路由请求时,需要共享这些密钥。

This makes the application stateful.

这使应用程序成为有状态的。

With stateful applications, specific pieces of work (transactions) are executed with the context of previous related transactions in mind. Server-side sessions or encrypted CSRF cookies are examples of widely used technologies inside the ASP.NET landscape that make an application stateful. The subsequent requests either happen on an connection being kept open, or need information that has been used in previous transactions. With sessions this can be data that has been set and shared in the session. With the cookies this is the information that has been generated in a previous request.

对于有状态应用程序,在执行特定工作(事务)时会考虑到先前相关事务的上下文。 服务器端会话或加密的CSRF cookie是ASP.NET环境中使应用程序有状态的广泛使用的技术的示例。 后续请求要么在保持打开状态的连接上发生,要么需要先前事务中已使用的信息。 对于会话,这可以是已在会话中设置和共享的数据。 对于cookie,这是先前请求中生成的信息。

However, a stateless application doesn’t need to know anything about the context of previous transactions. When doing a search query, the application doesn’t need to know about previous requests. When an error occurs, just start a new request.

但是,无状态应用程序不需要了解有关先前事务的上下文的任何信息。 进行搜索查询时,应用程序不需要了解以前的请求。 发生错误时,只需启动一个新请求即可。

使用服务器关联性来“解决”问题 (Using server affinity to ‘solve’ issues)

One approach to trying to solve the issue is by applying server affinity. Server affinity is referring to the ability to route all related requests of a specific client to one specific instance behind a load balancer.

解决问题的一种方法是应用服务器关联。 服务器相似性是指将特定客户端的所有相关请求路由到负载均衡器后面的一个特定实例的能力。

Image for post
Load balancer principle
负载均衡器原理

With the help of sticky sessions, a concept in a load balancer, all these requests can be sent to a specific upstream instance of the application behind a load balancer.

借助粘性会话(负载均衡器中的概念)的帮助,所有这些请求都可以发送到负载均衡器后面的应用程序的特定上游实例。

The problem with this approach, is that this process can fail. When an application is deployed and setup for automatic scaling on the basis of the load, you cannot guarantee that these instances always run. On the moment an instance became obsolete, an orchestrator (like Kubernetes) will shut down the obsolete application instance and session data will be lost. In regards to the cookies, the protection keys will be lost, and thus the next request would fail since the cookie can’t be validated.

这种方法的问题是该过程可能会失败。 部署应用程序并设置为根据负载自动缩放时,您不能保证这些实例始终运行。 在实例变得过时的时刻,协调器(如Kubernetes)将关闭过时的应用程序实例,并且会话数据将丢失。 关于cookie,保护密钥将丢失,并且由于无法验证cookie,因此下一个请求将失败。

In the ideal world every instance should be able to process each request.

在理想情况下,每个实例都应该能够处理每个请求。

集中式分布式存储解决有状态问题 (Centralized distributed storage to solve the stateful problem)

A more viable solution to solve the issues is by implementing centralized storage on application level. In this way data is made accessible in a centralized manner.

解决问题的一种更可行的解决方案是在应用程序级别上实现集中式存储。 这样,就可以以集中方式访问数据。

Since the implementation differs per technology, every subject(sessions, and cookies) will be covered one by one.

由于每种技术的实现方式不同,因此每个主题(会话和cookie)都将被一个一个地覆盖。

会话:分布式缓存以解决会话存储 (Sessions: distributed cache to solve session storage)

Microsoft created the distributed cache functionality to create the possibility of sharing session state between multiple application instances. With the help of implementations for SQL Server, Redis and NCache, a distributed cache can be easily setup and accessed with the help of an IDistributedCache interface. This can be connected to the cookie authentication.

Microsoft创建了分布式缓存功能,以创建在多个应用程序实例之间共享会话状态的可能性。 借助针对SQL Server,Redis和NCache的实现,可以轻松地通过IDistributedCache接口来设置和访问分布式缓存。 这可以连接到cookie身份验证。

Redis has been chosen for this example. With Redis is a centralized in-memory key-value cache and supports data structures like lists, sorted sets and strings.

本示例已选择Redis 。 Redis是一个集中式的内存键值缓存,并支持列表,排序集和字符串之类的数据结构。

Let’s start first by starting a Redis instance. The easiest way is to follow along is to use the official Redis Docker image. Another option would be to use a Redis Helm Chart to deploy Redis directly in a Kubernetes Cluster.

让我们首先启动Redis实例。 最简单的方法是使用官方Redis Docker映像 。 另一个选择是使用Redis Helm Chart将Redis直接部署在Kubernetes集群中。

With the command below, a new in-memory instance of Redis will be started at port 6379.

使用以下命令,将在端口6379处启动新的Redis内存实例。

docker run -p 6379:6379 --name some-redis -d redis

Inside your ASP.NET Core MVC Application, you are now able to install the required NuGet package for Redis Distributed Cache. This package contains extensions methods add the right dependencies to the service collection of your application. This is done by adding the following code to the Startup.ConfigureServices function in the Startup.cs class.

现在,在ASP.NET Core MVC应用程序内部,您可以为Redis分布式缓存安装所需的NuGet程序包 。 该程序包包含扩展方法,这些方法将正确的依赖项添加到应用程序的服务集合中。 这是通过将以下代码添加到Startup.cs类中的Startup.ConfigureServices函数中来完成的。

services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = "localhost";
});

Inside the Configuration property, a connection string can be set. For non standard settings the configuration reference can be consulted. Since the Redis instance runs on the default port at the local host, the current value would suffice.

在配置属性中,可以设置连接字符串。 对于非标准设置, 可以参考配置参考 。 由于Redis实例在本地主机的默认端口上运行,因此当前值就足够了。

Next, the session configuration needs to be added to the service collection. This is done by adding the AddSession extension method to the Startup.ConfigureServices method. This need to appended to the earlier added extension method, just like below:

接下来,需要将会话配置添加到服务集合中。 这可以通过将AddSession扩展方法添加到Startup.ConfigureServices方法中来完成。 这需要附加到之前添加的扩展方法中,如下所示:

services.AddStackExchangeRedisCache(options =>
{
    options.Configuration = "localhost";
});


services.AddSession(options =>
{
  options.IdleTimeout = TimeSpan.FromMinutes(20);
  options.Cookie.HttpOnly = true;
  options.Cookie.IsEssential = true;
});
  • To make sessions work, the session middleware makes use of a cookie containing a unique identifier. Sessions timeout after a specific idle time or when the browser gets closed. This can be configured in the IdleTimeout property.

    为了使会话正常工作,会话中间件使用包含唯一标识符的cookie。 在特定的空闲时间之后或浏览器关闭时,会话超时。 可以在IdleTimeout属性中进行配置。
  • Since the cookie is merely for identification of the client, the HttpOnly property needs to be set. This prevents that extra information can be added at the client to the cookie.

    由于cookie仅用于标识客户端,因此需要设置HttpOnly属性。 这样可以防止在客户端将额外的信息添加到cookie。
  • At last, the cookie is set as essential by the IsEssential property. This makes sure the cookie gets bypassed by the cookie consent functionality that is available for GPDR purposes.

    最后,通过IsEssential属性将cookie设置为必不可少的。 这可以确保Cookie可以通过可用于GPDR的cookie同意功能绕过。

To finally enable the session middleware, UseSession needs to be added to the request pipeline. The order of middleware is important. Call it after UseRouting and before Use Endpoints. The Startup class should look more or less as follows:

为了最终启用会话中间件,需要将UseSession添加到请求管道中。 中间件的顺序很重要。 在UseRouting之后和Use Endpoints之前调用它。 Startup类应大致如下所示:

Copy
public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }


    public IConfiguration Configuration { get; }


    public void ConfigureServices(IServiceCollection services)
    {
        services.AddStackExchangeRedisCache(options =>
        {
            options.Configuration = "localhost";
        });


        services.AddSession(options =>
        {
            options.IdleTimeout = TimeSpan.FromMinutes(20);
            options.Cookie.HttpOnly = true;
            options.Cookie.IsEssential = true;
        });


        services.AddControllersWithViews();
        services.AddRazorPages();
    }


    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        app.UseRouting();


        app.UseSession();


        app.UseEndpoints(endpoints =>
        {
            endpoints.MapDefaultControllerRoute();
            endpoints.MapRazorPages();
        });
    }
}

And that’s it. On the HttpContext property, inside an action method of a MVC controller, sessions can be set and retrieved. The distributed cache inplementation is responsible to save the session inside the Redis instance.

就是这样。 在HttpContext属性的MVC控制器的操作方法内部,可以设置和检索会话。 分布式缓存补充负责将会话保存在Redis实例中。

// Sets a string value with a key on the current session
HttpContext.Session.SetString(SessionKeyName, “value”);// Gets a string value by a key from the current session
var value = HttpContext.Session.GetString(SessionKeyName);

Cookies:使用Data Protection API创建集中式保护密钥 (Cookies: using Data Protection API to create centralized protection keys)

When making use of cookie authentication or CSRF cookies, the web application needs to save sensitive information client-side. Since clients are insecure because of fact that cookie information can be visible, Microsoft implemented the Data Protection API functionality to be able to secure the cookie information. With the help of a provider and protection keys, information can be protected and unprotected.

使用cookie身份验证或CSRF cookie时,Web应用程序需要在客户端保存敏感信息。 由于客户端由于可见cookie信息的事实是不安全的,因此Microsoft实施了Data Protection API功能以能够保护cookie信息。 借助提供者和保护密钥,可以保护和不保护信息。

The Data Protection API saves on default the protection keys in a folder on the operating system. When running in a Docker container or on Kubernetes, the keys are not not persisted.

默认情况下,Data Protection API将保护密钥保存在操作系统的文件夹中。 在Docker容器中或Kubernetes上运行时,密钥不会持久存在。

This is a problem when scaling out because every instance generates different protection keys on startup. When routing client requests over different instances, errors will occur because the app can’t unprotect cookies from different instances with different protection keys.

扩展时会出现问题,因为每个实例在启动时都会生成不同的保护密钥。 当在不同实例上路由客户端请求时,将发生错误,因为该应用无法使用不同的保护密钥来取消保护cookie免受不同实例的攻击。

Microsoft created multiple key storage provider implementations to change the storage location of the protection keys. These include Azure Storage, Windows Registry and Redis. Since we have already an Redis instance running, the Redis key storage provider will be used to demonstrate how the implementation should be done.

Microsoft创建了多个密钥存储提供程序实现,以更改保护密钥的存储位置。 其中包括Azure存储,Windows注册表和Redis。 由于我们已经在运行Redis实例,因此将使用Redis密钥存储提供程序来演示实现的方式。

To be able to use the needed extension method, a NuGet package is needed. The package, Microsoft.AspNetCore.DataProtection.StackExchangeRedis, uses the same Redis client as the distributed cache package. After adding the NuGet package, the implementation is done by adding the following code inside the Startup.ConfigureServices method:

为了能够使用所需的扩展方法,需要一个NuGet包。 包Microsoft.AspNetCore.DataProtection.StackExchangeRedis ,使用与分布式缓存包相同的Redis客户端。 添加NuGet程序包后,通过在Startup.ConfigureServices方法内添加以下代码来完成实现:

var redis = ConnectionMultiplexer.Connect("<URI>");
services.AddDataProtection()
  .PersistKeysToStackExchangeRedis(redis, "DataProtection-Keys");

The URI property accepts a connection string in the same format that was supplied to the distributed cache implementation. To support different applications with their keys, it’s suggested to create a unique Redis key for their data protection keys. The application will consult on startup whether there are data protection keys available and will generate them if they are not generated yet.

URI属性接受与提供给分布式缓存实现相同格式的连接字符串。 为了使用其密钥支持不同的应用程序,建议为其数据保护密钥创建一个唯一的Redis密钥。 应用程序将在启动时咨询是否有可用的数据保护密钥,如果尚未生成,则会生成它们。

摘要 (Summary)

During this article we’ve implemented two solutions for two technologies to be able to scale out a stateful application. With the help of a Redis instance, information can be shared between the instances.

在本文中,我们为两种技术实现了两种解决方案,以便能够扩展有状态的应用程序。 借助Redis实例,可以在实例之间共享信息。

When scaling up an application, additional resources are added to the existing infrastructure components. When scaling out an application, a new instance gets created with its own dedicated resources. This happens in parallel of the existing instance and is in general harder to setup.

扩展应用程序时,会将其他资源添加到现有的基础结构组件中。 扩展应用程序时,将使用其自己的专用资源创建一个新实例。 这与现有实例并行发生,并且通常更难设置。

A stateful application makes use of information that is shared over multiple transactions. With a stateless application, requests can be processed without needing any information of previous requests.

有状态应用程序利用在多个事务中共享的信息。 使用无状态应用程序,可以处理请求而无需先前请求的任何信息。

IDistributedCache is a viable solution to share server-side session information between multiple instances of an application.

IDistributedCache是​​在多个应用程序实例之间共享服务器端会话信息的可行解决方案。

Sharing the Data Protection keys centrally will solve the scalability issue for authentication and CSRF cookies.

集中共享数据保护密钥将解决身份验证和CSRF Coo​​kie的可伸缩性问题。

翻译自: https://medium.com/swlh/building-horizontal-scalable-stateful-applications-with-asp-net-core-1db270d24646

asp.net菜单栏伸缩

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值