netcore 内存限制_[翻译] 使用 Serverless 和 .NET Core 构建飞速发展的架构
作者:Samuele Resca
Serverless 技術(shù)為開發(fā)人員提供了一種快速而獨(dú)立的方式將實(shí)現(xiàn)投入生產(chǎn)。這種技術(shù)在企業(yè)的技術(shù)棧中日益流行,自 2017 年以來,它一直是 ThoughtWorks 技術(shù)雷達(dá)的實(shí)驗(yàn)級別的技術(shù)[譯注:技術(shù)雷達(dá)是 ThoughtWorks 每半年發(fā)布的前沿技術(shù)解析]。
本篇文章的第一部分介紹了有關(guān) Serverless 計(jì)算的基本概念。第二部分展示了如何構(gòu)建 .NET Core 的 Lambda 函數(shù),其中使用了 AWS 的 Serverless 框架。
Serverless 計(jì)算的好處
Serverless 技術(shù)是 FaaS(功能即服務(wù))技術(shù)體系的一部分。隨著云計(jì)算的采用,這些技術(shù)變得越來越受歡迎。如今,serverless 實(shí)現(xiàn)被提升為云計(jì)算提供商的首選技術(shù),無論是私有云還是公有云。
此外,典型的軟件服務(wù)和系統(tǒng)會通過在內(nèi)存中保留大量數(shù)據(jù)并在復(fù)雜數(shù)據(jù)源中寫入成批數(shù)據(jù)來完成操作。
然而一般而言,像 Serverless 一樣的 FaaS 技術(shù)旨在通過盡可能快地處理許多小請求和事件,來使我們的系統(tǒng)保持快速響應(yīng)。Serverless 組件通常與運(yùn)行它們的云服務(wù)商所提供的事件緊密耦合:一個(gè)通知、一個(gè)隊(duì)列調(diào)度的事件或者一個(gè)來自 API 網(wǎng)關(guān)的請求,都被視為此組件中包含的一小部分計(jì)算的觸發(fā)器。這也就是云服務(wù)商的定價(jià)系統(tǒng)基于請求數(shù)而不是基于計(jì)算時(shí)間的主要原因。
再者,serverless 組件通常在執(zhí)行時(shí)間上有一些限制。與每種技術(shù)一樣,serverless 并不適合每一個(gè)解決方案和系統(tǒng)。但是事實(shí)上,它確實(shí)簡化了軟件工程師的一些工作,lambda 部署周期通常很快,開發(fā)人員只需要做少量工作就可以快速將新功能投入生產(chǎn)。此外,使用 serverless 技術(shù)構(gòu)建組件意味著開發(fā)人員無需擔(dān)心擴(kuò)展問題或故障,讓云提供商去關(guān)心這些問題吧。
最后,我們還應(yīng)該知道 serverless 函數(shù)是無狀態(tài)的。因此,基于此技術(shù)構(gòu)建的每個(gè)系統(tǒng)都更加模塊化和松耦合。
Serverless 的痛點(diǎn)
但是這種能力和敏捷性卻不是沒有代價(jià)的。首先,serverless 函數(shù)是在云上執(zhí)行的,它們通常由與云提供商緊密耦合的事件觸發(fā),因此調(diào)試它們并不容易。這就是為什么要使它的作用域保持盡可能小,并且始終將函數(shù)的核心邏輯與外部組件和事件分隔開的原因。此外,用單元測試和集成測試覆蓋 serverless 代碼非常重要。
其次,就像微服務(wù)架構(gòu)一樣,它具有大量的服務(wù),但是關(guān)注的范圍很小,因此很難對 serverless 的組件進(jìn)行監(jiān)控,某些問題也很難檢測??傊?#xff0c;很難對不同的 serverless 組件之間的體系結(jié)構(gòu)和依賴性有一個(gè)全面的認(rèn)識。因此,云提服務(wù)商和第三方公司都在提供監(jiān)控和系統(tǒng)分析功能的一體式工具上投入了大量資金。
體驗(yàn)一下 serverless 計(jì)算
現(xiàn)如今,根據(jù)業(yè)務(wù)需求快速進(jìn)化的架構(gòu)以往任何時(shí)候都更為重要。數(shù)據(jù)驅(qū)動(dòng)的體驗(yàn)是這個(gè)過程的一部分。此外,在發(fā)布新功能之前,我們應(yīng)該實(shí)現(xiàn)MVP(譯注:最小可行化產(chǎn)品)并在部分客戶群上測試它。如果實(shí)驗(yàn)結(jié)果是肯定的,則值得在MVP上進(jìn)行投資,以將其轉(zhuǎn)化為我們產(chǎn)品的功能。
是的,serverless 計(jì)算提供了這樣一種方法,可以在不考慮基礎(chǔ)設(shè)施的情況下快速進(jìn)化我們的架構(gòu)。Serverless 輕量級開銷提供了一種實(shí)現(xiàn)一次性 MVP 的方法,用于試驗(yàn)新功能和新特性。此外,它們還可以很容易地啟動(dòng)和關(guān)閉。
使用 .NET Core 來實(shí)現(xiàn) AWS Lambda 函數(shù)
這一節(jié)將介紹使用 .NET Core 的一些 AWS Lambdas 的簡單實(shí)現(xiàn)。該例子涉及三個(gè)關(guān)鍵技術(shù):
AWS 是承載我們 serverless 功能的云服務(wù)商;
serverless 框架,它是將 Lambdas 放入 AWS 的非常有用的工具。作為一個(gè)通用的框架,它兼容所有主要的云服務(wù)商;
.NET Core 是微軟提供的開源的、跨平臺的框架;
我們將要討論的示例也放在了 GitHub 上,URL 如下:?serverless/examples/aws-dotnet-rest-api-with-dynamodb。該示例是 serverless 框架提供的一些模板項(xiàng)目的一部分。
AWS Lambda 項(xiàng)目遵循以下功能架構(gòu):
總結(jié)一下,該功能實(shí)現(xiàn)了對數(shù)據(jù)的一些讀取/寫入操作??蛻舳送ㄟ^API網(wǎng)關(guān)發(fā)出HTTP請求,lambda 項(xiàng)目定義了三個(gè)函數(shù):GetItem、InsertItem 和 UpdateItem。它們都對 DynamoDB 表進(jìn)行操作。
項(xiàng)目結(jié)構(gòu)
我們將要實(shí)現(xiàn)的解決方案具有以下項(xiàng)目結(jié)構(gòu):
src/DotNetServerless.Application 該項(xiàng)目包含了由 Serverless 執(zhí)行的核心邏輯;
src/DotNetServerless.Lambda 該項(xiàng)目包含了 Serverless 函數(shù)的入口點(diǎn)以及所有與 AWS 緊密耦合的組件;
tests/DotNetServerless.Tests 該項(xiàng)目包含了 Serverless 功能的單元測試和集成測試;
領(lǐng)域項(xiàng)目
讓我們從 application 層開始分析。項(xiàng)目的核心實(shí)體是 Item 類,它表示 DynamoDB(譯注:AWS的一種數(shù)據(jù)庫) 表中存儲的實(shí)體:
using Amazon.DynamoDBv2.DataModel;namespace DotNetServerless.Application.Entity
{
public class Item
{
[DynamoDBHashKey]
public string Id { get; set; }
[DynamoDBRangeKey]
public string Code { get; set; }
[DynamoDBProperty]
public string Description { get; set; }
[DynamoDBProperty]
public bool IsChecked { get; set; }
}
}
實(shí)體的字段使用了一些特性進(jìn)行修飾,以便使用 DynamoDb 存儲模型映射它們。Item 實(shí)體被 IItemsRepository 接口引用,該接口定義用于存儲數(shù)據(jù)的操作:
using System.Collections.Generic;using System.Threading;
using System.Threading.Tasks;
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.DataModel;
using Amazon.DynamoDBv2.DocumentModel;
using DotNetServerless.Application.Entities;
using DotNetServerless.Application.Infrastructure.Configs;
namespace DotNetServerless.Application.Infrastructure.Repositories
{
public interface IItemRepository
{
Task> GetById(string id, CancellationToken cancellationToken);Task Save(Item item, CancellationToken cancellationToken);
}public class ItemDynamoRepository : IItemRepository
{private readonly AmazonDynamoDBClient _client;private readonly DynamoDBOperationConfig _configuration;public ItemDynamoRepository(DynamoDbConfiguration configuration,
IAwsClientFactory clientFactory){
_client = clientFactory.GetAwsClient();
_configuration = new DynamoDBOperationConfig
{
OverrideTableName = configuration.TableName,
SkipVersionCheck = true
};
}public async Task Save(Item item, CancellationToken cancellationToken){using (var context = new DynamoDBContext(_client))
{await context.SaveAsync(item, _configuration, cancellationToken);
}
}public async Task> GetById(string id, CancellationToken cancellationToken)
{var resultList = new List();using (var context = new DynamoDBContext(_client))
{var scanCondition = new ScanCondition(nameof(Item.Id), ScanOperator.Equal, id);var search = context.ScanAsync(new[] {scanCondition}, _configuration);while (!search.IsDone)
{var entities = await search.GetNextSetAsync(cancellationToken);
resultList.AddRange(entities);
}
}return resultList;
}
}
}
IItemRepository 的實(shí)現(xiàn)定義了兩個(gè)基本操作:
Save,允許調(diào)用者插入和更新實(shí)體;
GetById,根據(jù) ID 返回對象;
最后,DotNetServerless.Application 的頂層是 Handler 部分。并且
,整個(gè) application 項(xiàng)目都基于中介模式,以保證 AWS 函數(shù)和核心邏輯之間的松散耦合。讓我們以創(chuàng)建項(xiàng)目處理程序的定義為例:
using System.Threading;
using System.Threading.Tasks;
using DotNetServerless.Application.Entities;
using DotNetServerless.Application.Infrastructure.Repositories;
using DotNetServerless.Application.Requests;
using MediatR;
namespace DotNetServerless.Application.Handlers
{
public class CreateItemHandler : IRequestHandler<CreateItemRequest, Item>
{
private readonly IItemRepository _itemRepository;
public CreateItemHandler(IItemRepository itemRepository){
_itemRepository = itemRepository;
}
public async TaskHandle(CreateItemRequest request, CancellationToken cancellationToken){
var item = request.Map();
item.Id = Guid.NewGuid().ToString();
await _itemRepository.Save(item, cancellationToken);
return item;
}
}
}
如您所見,代碼非常簡單。CreateItemHandler 實(shí)現(xiàn)了 IRequestHandler,它使用內(nèi)置的依賴注入來解析 IItemRepository 接口。處理程序的 Handler 方法僅將傳入的請求與Item實(shí)體映射,并調(diào)用IItemRepository接口提供的Save方法。
函數(shù)項(xiàng)目
函數(shù)項(xiàng)目包含 lambda 功能的入口點(diǎn)。它定義了三個(gè)函數(shù)類,它們表示 AWS 的 lambda:CreateItemFunction, GetItemFunction 和 UpdateItemFunction; 稍后我們將看到,每個(gè)函數(shù)都將使用 API 網(wǎng)關(guān)的特定路由進(jìn)行映射。
讓我們以 CreateItem 函數(shù)為例,對函數(shù)定義進(jìn)行一些深入探討:
using System;using System.Threading.Tasks;
using Amazon.Lambda.APIGatewayEvents;
using Amazon.Lambda.Core;
using DotNetServerless.Application.Requests;
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
namespace DotNetServerless.Lambda.Functions
{
public class CreateItemFunction
{
private readonly IServiceProvider _serviceProvider;
public CreateItemFunction() : this(Startup
.BuildContainer()
.BuildServiceProvider()){
}
public CreateItemFunction(IServiceProvider serviceProvider){
_serviceProvider = serviceProvider;
}
[LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]
public async TaskRun(APIGatewayProxyRequest request){
var requestModel = JsonConvert.DeserializeObject(request.Body);var mediator = _serviceProvider.GetService();var result = await mediator.Send(requestModel);return new APIGatewayProxyResponse { StatusCode = 201, Body = JsonConvert.SerializeObject(result)};
}
}
}
上面提到的代碼定義了函數(shù)的入口點(diǎn)。首先,它聲明一個(gè)構(gòu)造函數(shù),并使用Startup類公開的BuildContainer和BuildServiceProvider方法。稍后我們將看到,這些方法是為初始化依賴項(xiàng)注入容器而提供的。CreateItem 函數(shù)的 Run 方法使用 Lambda 序列器屬性進(jìn)行修飾,這意味著它是函數(shù)的入口點(diǎn)。此外,運(yùn)行函數(shù)使用 APIGatewayProxyRequest 請求和 APIGatewayProxyReposne 作為 lambda 計(jì)算的輸入和輸出。
依賴注入
該項(xiàng)目使用了 .NET Core 內(nèi)置的依賴注入。Startup 類定義了 BuildContainer 靜態(tài)方法,該方法返回一個(gè)新的 ServiceCollection,其中包含實(shí)體之間的依賴關(guān)系映射:
using System.IO;using DotNetServerless.Application.Infrastructure;
using DotNetServerless.Application.Infrastructure.Configs;
using DotNetServerless.Application.Infrastructure.Repositories;
using DotNetServerless.Lambda.Extensions;
using MediatR;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace DotNetServerless.Lambda
{
public class Startup
{
public static IServiceCollection BuildContainer(){
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddEnvironmentVariables()
.Build();
return ConfigureServices(configuration);
}
private static IServiceCollection ConfigureServices(IConfigurationRoot configurationRoot){
var services = new ServiceCollection();
services
.AddMediatR()
.AddTransient(typeof(IAwsClientFactory<>), typeof(AwsClientFactory<>))
.AddTransient()
.BindAndConfigure(configurationRoot.GetSection("DynamoDbConfiguration"), new DynamoDbConfiguration())
.BindAndConfigure(configurationRoot.GetSection("AwsBasicConfiguration"), new AwsBasicConfiguration());return services;
}
}
}
Startup使用ConfigureServices初始化新的ServiceCollection并與其一起解決依賴關(guān)系。此外,它還使用 BindAndConfigure 方法創(chuàng)建一些配置對象。BuildContainer方法將由函數(shù)調(diào)用,以解決依賴項(xiàng)。
測試我們的代碼
如前所述,測試一下我們的代碼,對于持續(xù)集成和交付是非常重要的,尤其是在lambda項(xiàng)目中。在這種情況下,測試將覆蓋 IMediator 接口和處理程序之間的集成。此外,它們還覆蓋了依賴項(xiàng)注入部分。讓我們看看 CreateItemFunctionTests 的實(shí)現(xiàn):
using System.Threading;using System.Threading.Tasks;
using Amazon.Lambda.APIGatewayEvents;
using DotNetServerless.Application.Entities;
using DotNetServerless.Application.Infrastructure.Repositories;
using DotNetServerless.Application.Requests;
using DotNetServerless.Lambda;
using DotNetServerless.Lambda.Functions;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Moq;
using Newtonsoft.Json;
using Xunit;
namespace DotNetServerless.Tests.Functions
{
public class CreateItemFunctionTests
{
public CreateItemFunctionTests(){
_mockRepository = new Mock();
_mockRepository.Setup(_ => _.Save(It.IsAny(), It.IsAny())).Returns(Task.CompletedTask);var serviceCollection = Startup.BuildContainer();
serviceCollection.Replace(new ServiceDescriptor(typeof(IItemRepository), _ => _mockRepository.Object,
ServiceLifetime.Transient));
_sut = new CreateItemFunction(serviceCollection.BuildServiceProvider());
}private readonly CreateItemFunction _sut;private readonly Mock _mockRepository;
[Fact]public async Task run_should_trigger_mediator_handler_and_repository(){await _sut.Run(new APIGatewayProxyRequest {Body = JsonConvert.SerializeObject(new CreateItemRequest())});
_mockRepository.Verify(_ => _.Save(It.IsAny(), It.IsAny()), Times.Once);
}
[Theory]
[InlineData(201)]public async Task run_should_return_201_created(int statusCode){var result = await _sut.Run(new APIGatewayProxyRequest {Body = JsonConvert.SerializeObject(new CreateItemRequest())});
Assert.Equal(result.StatusCode, statusCode);
}
}
}
如您所見,上述代碼執(zhí)行了我們的函數(shù),并且對已注入的依賴項(xiàng)執(zhí)行一些驗(yàn)證,并驗(yàn)證 IItemRepository 公開的 Save 方法是否被調(diào)用。因?yàn)橐恍┰?#xff0c;測試類并沒有覆蓋 DynamoDb 的特性。此外,當(dāng)我們將復(fù)雜的實(shí)體和操作結(jié)合在一起時(shí),可以使用 Docker 容器通過一些集成測試來覆蓋數(shù)據(jù)庫部分。對了,提到 .NET Core 和 AWS 的話題,.NET AWS 團(tuán)隊(duì)有一個(gè)很好的工具來改進(jìn) lambda 的測試:LambdaTestTool
部署項(xiàng)目
讓我們來看看如何將項(xiàng)目導(dǎo)入AWS。為此,我們將使用?serverless 框架。該框架的定義是:
serverless 框架是一個(gè) CLI 工具,允許用戶構(gòu)建和部署自動(dòng)縮放、按執(zhí)行付費(fèi)、事件驅(qū)動(dòng)的函數(shù)。
為了把 serverless 添加我們的項(xiàng)目,我們應(yīng)該執(zhí)行以下命令:
npm install serverless --save-dev定義基礎(chǔ)架構(gòu)
默認(rèn)情況下,基礎(chǔ)架構(gòu)的定義將放在 serverless.yml 文件中。該文件看起來像這樣:
service: ${file(env.configs.yml):feature}frameworkVersion: ">=1.6.0 <2.1.0"
provider:
name: aws
stackName: ${file(env.configs.yml):feature}-${file(env.configs.yml):environment}
runtime: dotnetcore2.1
region: ${file(env.configs.yml):region}
accountId: ${file(env.configs.yml):accountId}
environment:
DynamoDbConfiguration__TableName: ${file(env.configs.yml):dynamoTable}
iamRoleStatements:
- Effect: Allow
Action:
- dynamodb:*
Resource: "arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.environment.DynamoDbConfiguration__TableName}"
package:
artifact: bin/release/netcoreapp2.1/deploy-package.zip
functions:
create:
handler: DotNetServerless.Lambda::DotNetServerless.Lambda.Functions.CreateItemFunction::Run
events:
- http:
path: items
method: post
cors: true
get:
handler: DotNetServerless.Lambda::DotNetServerless.Lambda.Functions.GetItemFunction::Run
events:
- http:
path: items/{id}
method: get
cors: true
update:
handler: DotNetServerless.Lambda::DotNetServerless.Lambda.Functions.UpdateItemFunction::Run
events:
- http:
path: items
method: put
cors: true
resources:
Resources:
ItemsDynamoDbTable:
Type: 'AWS::DynamoDB::Table'
DeletionPolicy: Retain
Properties:
AttributeDefinitions:
- AttributeName: Id
AttributeType: S
- AttributeName: Code
AttributeType: S
KeySchema:
- AttributeName: Id
KeyType: HASH
- AttributeName: Code
KeyType: RANGE
ProvisionedThroughput:
ReadCapacityUnits: 1
WriteCapacityUnits: 1
TableName: ${self:provider.environment.DynamoDbConfiguration__TableName}
以上代碼使用 AWS 的 cloud formation 對基礎(chǔ)架構(gòu)進(jìn)行一些操作。provider 節(jié)點(diǎn)定義了有關(guān) lambda 的某些信息,例如堆棧名稱、運(yùn)行時(shí)以及有關(guān)AWS賬戶的一些信息。此外,它還描述了 lambda 的角色和授權(quán),例如,應(yīng)該允許 lambda 對 DynamoDb 表執(zhí)行操作。functions 節(jié)點(diǎn)定義了不同的 lambda 函數(shù),并將其與特定的 HTTP 路徑進(jìn)行映射。最后,resources 節(jié)點(diǎn)用于設(shè)置 DynamoDB 表模式。
配置文件
serverless.yml 定義通常與另一個(gè) YAML 文件結(jié)合使用,該文件僅定義與環(huán)境相關(guān)的配置。例如,DynamoDbConfiguration__TableName?節(jié)點(diǎn)就是這種情況,該節(jié)點(diǎn)使用以下語法從另一個(gè) YAML 文件獲取信息:${file(env.configs.yml):dynamoTable}。以下代碼段顯示了 env.config.yml 文件的一個(gè)示例:
feature: version: 1.0.0.0region: environment: accountId: dynamoTable:最后的想法
這篇文章涵蓋了一些關(guān)于 serverless 計(jì)算的理論主題,以及 .Net Core 實(shí)現(xiàn) lambda 函數(shù)的例子。著重講解了如何使用 serverless 計(jì)算來快速推進(jìn)我們的架構(gòu)。此外,勇于嘗試是一個(gè)不斷發(fā)展的產(chǎn)品很關(guān)鍵的一方面,它對于快速適應(yīng)業(yè)務(wù)的變化是很重要的。
最后,您可以在以下存儲庫中找到一些 serverless 的 lambda 示例。
serverless/examples/aws-dotnet-rest-api-with-dynamodb
原文鏈接:https://www.cnblogs.com/Rwing/p/fast-growing-architectures-with-serverless-and-net-core.html
.NET社區(qū)新聞,深度好文,歡迎訪問公眾號文章匯總?http://www.csharpkit.com?
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的netcore 内存限制_[翻译] 使用 Serverless 和 .NET Core 构建飞速发展的架构的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python字符串转日期_Python:
- 下一篇: 切面是异步还是同步操作‘_【 .NET