请选择 进入手机版 | 继续访问电脑版
搜索
房产
装修
汽车
婚嫁
健康
理财
旅游
美食
跳蚤
二手房
租房
招聘
二手车
教育
茶座
我要买房
买东西
装修家居
交友
职场
生活
网购
亲子
情感
龙城车友
找美食
谈婚论嫁
美女
兴趣
八卦
宠物
手机

[翻译] 使用 Serverless 和 .NET Core 构建飞速发展的架构

[复制链接]
查看: 9|回复: 0

1万

主题

2万

帖子

5万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
52000
发表于 2019-12-3 00:29 | 显示全部楼层 |阅读模式
原文:Fast growing architectures with serverless and .NET Core
作者:Samuele Resca
Serverless 技术为开辟职员供给了一种快速而自力的方式将实现投入生产。这类技术在企业的技术栈中日益流行,自 2017 年以来,它不停是 ThoughtWorks 技术雷达的实行级此外技术[译注:技术雷达是 ThoughtWorks 每半年公布的前沿技术分析]。
本篇文章的第一部分先容了有关 Serverless 盘算的底子概念。第二部分展现了怎样构建 .NET Core 的 Lambda 函数,其中利用了 AWS 的 Serverless 框架。
Serverless 盘算的好处

Serverless 技术是 FaaS(功用即办事)技术系统的一部分。随着云盘算的采取,这些技术变得越来越受接待。现在,serverless 实现被提拔为云盘算供给商的首选技术,不管是私有云还是私有云。
此外,典型的软件办事和系统会经过在内存中保存大量数据并在复杂数据源中写入成批数据来完成操纵。
但是一样平常而言,像 Serverless 一样的 FaaS 技术旨在经过尽大要快地处置惩罚很多小请求和变乱,来使我们的系统连结快速响应。Serverless 组件凡是与运转它们的云办事商所供给的变乱紧密耦合:一个看护、一个行列调节的变乱大要一个来自 API 网关的请求,都被视为此组件中包含的一小部分盘算的触发器。这也就是云办事商的定价系统基于请求数而不是基于盘算时候的严重原因原由。
再者,serverless 组件凡是在实行时候上有一些限制。与每种技术一样,serverless 并不适当每一个治理计划和系统。可是究竟上,它确切简化了软件工程师的一些工作,lambda 安排周期凡是很快,开辟职员只需要做少许工作便可以快速将新功用投入生产。此外,利用 serverless 技术构建组件意味着开辟职员无需担忧扩大题目或故障,让云供给商去关心这些题目吧。
末端,我们还应当晓得 serverless 函数是无状态的。是以,基于此技术构建的每个系统都加倍模块化和松耦合。
Serverless 的痛点

可是这类本事和灵敏性却不是没有价格的。首先,serverless 函数是在云上实行的,它们凡是由与云供给商紧密耦合的变乱触发,是以调试它们并不轻易。这就是为什么要使它的感化域连结尽大要小,而且始终将函数的焦点逻辑与内部组件和变乱分离隔的原因原由。此外,用单元测试和集成测试覆盖 serverless 代码很是严重。
其次,就像微办事架构一样,它具有大量的办事,可是关注的范围很小,是以很难对 serverless 的组件举行监控,某些题目也很难检测。总之,很难对差此外 serverless 组件之间的系统结构和依靠性有一个周全的熟悉。是以,云提办事商和第三方公司都在供给监控和系统分析功用的一体式工具上投入了大量资金。
体验一下 serverless 盘算

现现在,按照营业需求快速进化的架构以往任何时候都更抓严重。数据驱动的体验是这个进程的一部分。此外,在公布新功用之前,我们应当实现MVP(译注:最小可行化产物)并在部分客户群上测试它。假照实行结果是必定的,则值得在MVP上举行投资,以将其转化为我们产物的功用。
是的,serverless 盘算供给了这样一种方式,可以在不考虑底子法子的情况下快速进化我们的架构。Serverless 轻量级开销供给了一种实现一次性 MVP 的方式,用于实验新功用和新特征。此外,它们还可以很轻易地启动和封闭。
利用 .NET Core 来实现 AWS Lambda 函数

这一节将先容利用 .NET Core 的一些 AWS Lambdas 的简单实现。该例子触及三个关键技术:

  • AWS 是承载我们 serverless 功用的云办事商;
  • serverless 框架,它是将 Lambdas 放入 AWS 的很是有用的工具。作为一个通用的框架,它兼容全数严重的云办事商;
  • .NET Core 是微软供给的开源的、跨平台的框架;
我们将要会商的示例也放在了 GitHub 上,URL 以下: serverless/examples/aws-dotnet-rest-api-with-dynamodb。该示例是 serverless 框架供给的一些模板项方针一部分。
AWS Lambda 项目依照以下功用架构:
[翻译] 使用 Serverless 和 .NET Core 构建飞速发展的架构  游戏 Screenshot-2018-11-25-at-00.15.33

总结一下,该功用实现了对数据的一些读取/写入操纵。客户端经过API网关发出HTTP请求,lambda 项目界说了三个函数:GetItem、InsertItem 和 UpdateItem。它们都对 DynamoDB 表举行操纵。
项目结构

我们将要实现的治理计划具有以下项目结构:

  • src/DotNetServerless.Application 该项目包含了由 Serverless 实行的焦点逻辑;
  • src/DotNetServerless.Lambda 该项目包含了 Serverless 函数的进口点以及全数与 AWS 紧密耦合的组件;
  • tests/DotNetServerless.Tests 该项目包含了 Serverless 功用的单元测试和集成测试;
范围项目

让我们从 application 层起头分析。项方针焦点实体是 Item 类,它表示 DynamoDB(译注:AWS的一种数据库) 表中存储的实体:
  1. 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; }  }}
复制代码
实体的字段利用了一些特征举行修饰,以便利用 DynamoDb 存储模子映照它们。Item 实体被 IItemsRepository 接口援用,该接口界说用于存储数据的操纵:
  1. 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 的实现界说了两个底子操纵:

  • Save,答应挪用者插入和更新实体;
  • GetById,按照 ID 返回工具;
末端,DotNetServerless.Application 的顶层是 Handler 部分。而且
,全部 application 项目都基于中介形式,以保证 AWS 函数和焦点逻辑之间的疏松耦合。让我们以建立项目处置惩罚步伐的界说为例:
  1. using System;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  {    private readonly IItemRepository _itemRepository;    public CreateItemHandler(IItemRepository itemRepository)    {      _itemRepository = itemRepository;    }    public async Task Handle(CreateItemRequest request, CancellationToken cancellationToken)    {      var item = request.Map();      item.Id = Guid.NewGuid().ToString();      await _itemRepository.Save(item, cancellationToken);      return item;    }  }}
复制代码
如您所见,代码很是简单。CreateItemHandler 实现了 IRequestHandler,它利用内置的依靠注入来分析 IItemRepository 接口。处置惩罚步伐的 Handler 方式仅将传入的请求与Item实体映照,并挪用IItemRepository接口供给的Save方式。
函数项目

函数项目包含 lambda 功用的进口点。它界说了三个函数类,它们表示 AWS 的 lambda:CreateItemFunction, GetItemFunction 和 UpdateItemFunction; 稍后我们将看到,每个函数都将利用 API 网关的特定路由举行映照。
让我们以 CreateItem 函数为例,对函数界说举行一些深入探讨:
  1. 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 Task Run(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)};    }  }}
复制代码
上面提到的代码界说了函数的进口点。首先,它声明一个机关函数,并利用Startup类公然的BuildContainer和BuildServiceProvider方式。稍后我们将看到,这些方式是为初始化依靠项注入容器而供给的。CreateItem 函数的 Run 方式利用 Lambda 序列器属性举行修饰,这意味着它是函数的进口点。此外,运转函数利用 APIGatewayProxyRequest 请求和 APIGatewayProxyReposne 作为 lambda 盘算的输入和输出。
依靠注入

该项目利用了 .NET Core 内置的依靠注入。Startup 类界说了 BuildContainer 静态方式,该方式返回一个新的 ServiceCollection,其中包含实体之间的依靠关系映照:
  1. 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并与其一路治理依靠关系。此外,它还利用 BindAndConfigure 方式建立一些设备工具。BuildContainer方式将由函数挪用,以治理依靠项。
测试我们的代码

如前所述,测试一下我们的代码,对于连续集成和托付黑白常严重的,特别是在lambda项目中。在这类情况下,测试将覆盖 IMediator 接口和处置惩罚步伐之间的集成。此外,它们还覆盖了依靠项注入部分。让我们看看 CreateItemFunctionTests 的实现:
  1. 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);    }  }}
复制代码
如您所见,上述代码实行了我们的函数,而且对已注入的依靠项实行一些考证,并考证 IItemRepository 公然的 Save 方式能否被挪用。由于一些原因原由,测试类并没有覆盖 DynamoDb 的特征。此外,当我们将复杂的实体和操纵团结在一路时,可以利用 Docker 容器经过一些集成测试来覆盖数据库部分。对了,提到 .NET Core 和 AWS 的话题,.NET AWS 团队有一个很好的工具来改良 lambda 的测试:LambdaTestTool
安排项目

让我们来看看怎样将项目导入AWS。为此,我们将利用 serverless 框架。该框架的界说是:
serverless 框架是一个 CLI 工具,答利用户构建和安排自动缩放、按实行付费、变乱驱动的函数。
为了把 serverless 增加我们的项目,我们应当实行以下命令:
  1. npm install serverless --save-dev
复制代码
界说底子架构

默许情况下,底子架构的界说将放在 serverless.yml 文件中。该文件看起来像这样:
[code]service: ${file(env.configs.yml):feature}frameworkVersion: ">=1.6.0

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Copyright © 2006-2014 妈妈网-中国妈妈第一,是怀孕、育儿、健康等知识交流传播首选平台 版权所有 法律顾问:高律师 客服电话:0791-88289918
技术支持:迪恩网络科技公司  Powered by Discuz! X3.2
快速回复 返回顶部 返回列表