热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

ASP.NET5withDapr初体验

分布式应用运行时Dapr目前已经发布了1.1.0版本,阿里云也在积极地为Dapr贡献代码和落地实践。作为一名开发者,自然也想玩一玩,看看Dapr带来的新“视”界到底是怎么样的。1关

分布式应用运行时Dapr目前已经发布了1.1.0版本,阿里云也在积极地为Dapr贡献代码和落地实践。作为一名开发者,自然也想玩一玩,看看Dapr带来的新“视”界到底是怎么样的。


1 关于Dapr

Dapr(Distributed Application Runtime)是一个开源、可移植、事件驱动的运行时。它使开发人员能够轻松地构建运行在云平台和边缘的弹性而微服务化的应用程序,无论是无状态还是有状态。Dapr 让开发人员能够专注于编写业务逻辑,而不是解决分布式系统的挑战,从而显著提高生产力并减少开发时间。此外,Dapr 也降低了大部分中小型企业基于微服务架构构建现代云原生应用的准入门槛。

Dapr 的核心构建模块 (或者说核心功能)如下:



  • 服务调用: 弹性服务与服务之间(service-to-service)调用可以在远程服务上启用方法调用,包括重试,无论远程服务在受支持的托管环境中运行在何处。



  • 状态管理:通过对键 / 值对的状态管理,可以很容易编写长时间运行、高可用性的有状态服务,以及同一个应用中的无状态服务。状态存储是可插入的,并且可以包括 Azure Cosmos 或 Redis,以及组件路线图上的其他组件,如 AWS DynamoDB 等。



  • 在服务之间发布和订阅消息(Pub/Sub):使事件驱动的架构能够简化水平可扩展性,并使其具备故障恢复能力。



  • 事件驱动的资源绑定:资源绑定和触发器在事件驱动的架构上进一步构建,通过从任何外部资源(如数据库、队列、文件系统、blob 存储、webhooks 等)接收和发送事件,从而实现可扩展性和弹性。例如,你的代码可以由 Azure EventHub 服务上的消息触发,并将数据写入 Azure CosmosDB。



  • 虚拟角色:无状态和有状态对象的模式,通过方法和状态封装使并发变得简单。Dapr 在其虚拟角色(Virtual Actors)运行时提供了许多功能,包括并发、状态、角色激活 / 停用的生命周期管理以及用于唤醒角色的计时器和提醒。



  • 服务之间的分布式跟踪:使用 W3C 跟踪上下文(W3C Trace Context)标准,轻松诊断和观察生产中的服务间调用,并将事件推送到跟踪和监视系统。



目前Dapr提供了如下所示的主流语言的SDK:

更多关于Dapr的介绍不是本文的重点,有兴趣的读者可以移步阅读:

(1)阿里巴巴的Dapr实践与探索

(2)Dapr是否会引领云原生中间件的未来

(3)分布式运行时 Dapr 知多少

本文的试玩会主要集中在服务调用(service invocation)和 发布订阅(pub / sub)上面,并且只会在入门小DEMO的程度,期望值过高的童鞋可以自行学习 或 绕道行走,毕竟我的时间也有限。


2 准备工作

一台Linux虚拟机

为了后面的DEMO,在VMware Workstation中准备一个Linux虚拟机环境,这里我选择的是CentOS 7.6。

在此虚拟机中设定静态IP地址(本示例为 192.168.2.100),关闭防火墙,设定主机名等一系列基本操作。


安装.NET 5 SDK

这里我的DEMO是基于local-host部署模式(也可以选择Kubernetes模式部署,但我没时间弄),因此给Linux安装一下.NET 5 SDK,命令如下:

添加受信源
sudo rpm -Uvh https://packages.microsoft.com/config/centos/7/packages-microsoft-prod.rpm
安装.NET 5 SDK
sudo yum install dotnet-sdk-5.0

安装Dapr CLI

官网提示直接在Linux下执行以下命令就可以将Dapr CLI下载到/usr/local/bin目录下:

wget -q https://raw.githubusercontent.com/dapr/cli/master/install/install.sh -O - | /bin/bash

不过由于网络原因,我选择了直接下载Release来安装:

(1)到github上下载1.1.0的release压缩包(dapr_linux_amd64.tar.gz),并将其传到Linux中。

(2)解压该压缩包,并将解压后的目录移动到/usr/local/bin目录下:

tar -zvxf dapr_linux_amd64.tar.gz

(3)通过输入 dapr 来验证是否安装成功:

此外,也可以通过 dapr --version 查看Dapr版本:

CLI version: 1.1.0
Runtime version:
1.1.0

 初始化Dapr

安装好Dapr CLI之后,就可以在Linux上初始化Dapr了,命令如下:

dapr init

这个命令会帮你做一些列的事情,包括但不限于 拉取一波docker镜像 & 运行一波docker容器,如下图所示:

可以看到,dapr, redis, zipkin都已经运行起来了。

为什么有redis?因为它会作为默认的pub/sub中间件为dapr提供具体的实现能力。

为什么会有zipkin?因为它会作为默认的tracing中间件为我们提供链路追踪的能力。

OK,到此为止,本地的Dapr运行时基础环境已基本就绪。


3 .NET 5 应用集成Dapr SDK

准备三个.NET WebAPI

这里我们准备了三个WebAPI项目,分别是订单服务、购物车服务 以及 商品服务。

具体的代码可以去github上查看,github地址为:https://github.com/EdisonChou/EDT.Dapr.Sample。


为所有WebAPI项目添加集成

为所有项目添加Dapr SDK的nuget包,这里是 Dapr.AspNetCore 组件。


为所有WebAPI项目注册Dapr

在StartUp类中,对Dapr Client进行注册,这里的AddDapr背后的操作其实就是给IoC容器注入了一个单例的DaprClient对象。

public void ConfigureServices(IServiceCollection services)
{
services.AddControllers()
.AddDapr();
......
}

4 服务调用示例

这里假设CartService要和ProductService进行通信,通过REST获取商品数据。这里,就可以借助Dapr提供的服务间调用的功能进行通信。其工作原理如下图所示:

 

这里使用的方式是通过DaprClient直接InvokeMethod进行服务间的通信,传递了两个重要的参数,一个是依赖服务的app-id(根据你部署时设定的名字来写),另一个是依赖接口的route。

具体如下代码所示:

[ApiController]
[Route(
"[controller]")]
public class CartController : ControllerBase
{
private readonly ILogger _logger;
private readonly DaprClient _daprClient;
public CartController(ILogger logger, DaprClient daprClient)
{
_logger
= logger;
_daprClient
= daprClient;
}
[HttpGet]
public async Task> Get()
{
_logger.LogInformation(
"[Begin] Query product data from Product Service");
var products = await _daprClient.InvokeMethodAsync>
(HttpMethod.Get,
"ProductService", "Product");
_logger.LogInformation($
"[End] Query product data from Product Service, data : {products.ToArray().ToString()}");
return products;
}
}

这里对应ProductService的接口默认返回一些假数据:

[ApiController]
[Route(
"[controller]")]
public class ProductController : ControllerBase
{
private static readonly string[] FakeProducts = new[]
{
"SKU1", "SKU2", "SKU3", "SKU4", "SKU5", "SKU6", "SKU7", "SKU8", "SKU9", "SKU10"
};
......
[HttpGet]
public IEnumerable Get()
{
_logger.LogInformation(
"[Begin] Query product data.");
var rng = new Random();
var result = Enumerable.Range(1, 5).Select(index => new SKU
{
Date
= DateTime.Now.AddDays(index),
Index
= rng.Next(1, 100),
Summary
= FakeProducts[rng.Next(FakeProducts.Length)]
})
.ToArray();
_logger.LogInformation(
"[End] Query product data.");
return result;
}
}

 然后,将这两个服务发布到Linux服务器上,当然,我们要通过dapr来部署,让.net application和dapr sidecar形成一体。

部署命令如下所示,可以看到我们既要为.net application指定端口,也要为dapr sidecar指定端口(这里主要为dapr指定了http端口,也可以为其指定grpc端口)。

dapr run --app-id CartService --app-port 5000 --dapr-http-port 5005 -- dotnet EDT.EMall.Cart.API.dll --urls "http://*:5000"
dapr run
--app-id ProductService --app-port 5010 --dapr-http-port 5015 -- dotnet EDT.EMall.Product.API.dll --urls "http://*:5010"

你会发现,当你run成功之后,会看到以下log,其中既有dapr的log,也有.net application的log,虽然他们是两个应用程序,但是你看到的它们是一体的。

最后,通过swagger来测试一下,结果如下,成功进行了服务调用。


5 消息发布及订阅示例

发布订阅模式(Publish-Subscribe)是众所周知且广泛使用的消息模式。这里我们假设OrderService的某个接口完成后就发布一个消息,告知订阅方有新订单的事件产生。

在Dapr中其工作原理如下图所示:

具体代码示例如下,借助DaprClient的PublishEvent接口实现消息发布:

[ApiController]
[Route(
"[controller]")]
public class OrderController : ControllerBase
{
private const string DaprPubSubName = "pubsub";
private readonly ILogger _logger;
private readonly DaprClient _daprClient;
public OrderController(ILogger logger, DaprClient daprClient)
{
_logger
= logger;
_daprClient
= daprClient;
}
[HttpPost]
public async Task Post(OrderDto orderDto)
{
_logger.LogInformation(
"[Begin] Create Order.");
var order = new Models.Order()
{
// some mapping
Id = orderDto.Id,
ProductId
= orderDto.ProductId,
Count
= orderDto.Count
};
// some other logic for order
var orderStockDto = new OrderStockDto()
{
ProductId
= orderDto.ProductId,
Count
= orderDto.Count
};
await _daprClient.PublishEventAsync(DaprPubSubName, "neworder", orderStockDto);
_logger.LogInformation($
"[End] Create Order Finished. Id : {orderStockDto.ProductId}, Count : {orderStockDto.Count}");
return order;
}
}

假设ProductService作为订阅方,需要消费这个事件,并扣减某个商品的库存。而基于Dapr,我们需要对ProductService添加一点配置:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
......
app.UseCloudEvents();
// 标准化的消息传递格式
app.UseEndpoints(endpoints =>
{
endpoints.MapSubscribeHandler();
// 订阅消费处理
......
});
}

然后,在ProductService中添加一个方法/接口 来作为订阅处理。

具体代码示例如下,需要注意的就是:

(1)作为消息处理接口,需要指定为HttpPost方式。

(2)需要指定Topic特性,并标注pubsubname 和 事件名。

private const string DaprPubSubName = "pubsub";
[HttpPost]
[Topic(DaprPubSubName,
"neworder")]
public Models.Product SubProductStock(OrderStockDto orderStockDto)
{
_logger.LogInformation($
"[Begin] Sub Product Stock, Stock Need : {orderStockDto.Count}.");
var product = _productService.GetProductById(orderStockDto.ProductId);
if (orderStockDto.Count <0 || orderStockDto.Count > product.Stock)
{
throw new InvalidOperationException("Invalid Product Count!");
}
product.Stock
= product.Stock - orderStockDto.Count;
_productService.SaveProduct(product);
_logger.LogInformation($
"[End] Sub Product Stock Finished, Stock Now : {product.Stock}.");
return product;
}

这里的DaprPubSubName是pubsub,这是因为Dapr默认的pubsub实现是基于Redis的,而在配置中为Redis设置的name就是 pubsub,因此对于我们入门的话,就不要去更改,或者和配置中的name保持一致。

[root@dapr-lab-server ~]# cat ~/.dapr/components/pubsub.yaml
apiVersion: dapr.io
/v1alpha1
kind: Component
metadata:
name: pubsub
spec:
type: pubsub.redis
metadata:
- name: redisHost
value: localhost:
6379
- name: redisPassword
value:
""

当然,我们也可以将默认的pubsub实现Redis换为熟悉的RabbitMQ。我们只需要更改上面的yml文件内容如下:

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: pubsub
-rq
spec:
type: pubsub.rabbitmq
version: v1
metadata:
- name: host
value:
"amqp://localhost:5672"
- name: durable
value:
true

然后,将这两个服务发布到Linux服务器上,当然,我们要通过dapr来部署,让.net application和dapr sidecar形成一体。

dapr run --app-id OrderService --app-port 5020 --dapr-http-port 5025 -- dotnet EDT.EMall.Order.API.dll --urls "http://*:5020"
dapr run
--app-id ProductService --app-port 5010 --dapr-http-port 5015 -- dotnet EDT.EMall.Product.API.dll --urls "http://*:5010"

run成功后,通过 dapr list 查看,可以看到三个服务都已经启动起来了,它们是三个由.net application + dapr sidecar 组成的“合体应用”。

最后,我们通过swagger来测试一下,测试结果如下图所示:

(1)OrderService:

(2)ProductService:

这里的99其实是假总库存100 - 消息传递过来的商品数量得到的,具体可以参考代码示例。


6 小结

本文总结了我试玩Dapr的一些经过,包括Dapr的Local环境搭建、.NET 5 Application与Dapr的集成 和 两个具体场景的小DEMO(服务调用 和 Pub/Sub)。

这里借助知乎上 iyacontrol 童鞋的评论(来源:https://www.zhihu.com/question/351298264),作为结尾:

Dapr 本身是一种 Sidecar 模式(虽然Dapr也提供了SDK,但是个人认为这并不是Dapr以后的发展方向)。Sidecar 模式的意义在于, 解耦了基础设施和核心业务

简单来看,Dapr的意义在于:



  • 对于小公司,甚至没有基础架构和中间件团队的公司,Dapr 提供了开箱即用的基础设施功能,可以让小公司轻松构建弹性,分布式应用



  • 对于中等单位,具备一定的基础架构能力,在使用Dapr的过程中,可能Dapr并不能完全满足需求,那么也可以在Dapr框架体系下,花费较小的成本进行自定义扩展



  • 对于大公司,Dapr 提供了一种思路。相信基础架构团队会越来越倾向于通过交付Sidecar的形式来提供基础设施



长远来看,Dapr背后的架构模式是符合未来架构趋势(多运行时架构)和云原生发展趋势的


代码示例

github:https://github.com/EdisonChou/EDT.Dapr.Sample


参考资料

Microsoft,《Dapr for .NET Developer》: 

Tony,《Dapr公开课》

 

作者:周旭龙

出处:https://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。


原文链接:https://www.cnblogs.com/edisonchou/p/dapr_1st_travel_with_aspnet5.html



推荐阅读
  • Java EE 平台集成了多种服务、API 和协议,旨在支持基于 Web 的多层应用程序开发。本文将详细介绍 Java EE 中的 13 种关键技术规范,帮助开发者更好地理解和应用这些技术。 ... [详细]
  • 从理想主义者的内心深处萌发的技术信仰,推动了云原生技术在全球范围内的快速发展。本文将带你深入了解阿里巴巴在开源领域的贡献与成就。 ... [详细]
  • 深入探讨:Actor模型如何解决并发与分布式计算难题
    在现代软件开发中,高并发和分布式系统的设计面临着诸多挑战。本文基于Akka最新文档,详细探讨了Actor模型如何有效地解决这些挑战,并提供了对并发和分布式计算的新视角。 ... [详细]
  • 对象存储与块存储、文件存储等对比
    看到一篇文档,讲对象存储,好奇,搜索文章,摘抄,学习记录!背景:传统存储在面对海量非结构化数据时,在存储、分享与容灾上面临很大的挑战,主要表现在以下几个方面:传统存储并非为非结 ... [详细]
  • Android 属性 allowBackup 的安全风险分析
    在 Android API Level 8 及以上版本中,系统提供了一种机制来备份和恢复应用程序数据。通过设置 allowBackup 属性,开发者可以控制是否允许这种备份和恢复功能。然而,这一功能也带来了潜在的安全风险。 ... [详细]
  • 在开发板的启动选项中看到如下两行:7:LoadBootLoadercodethenwritetoFlashviaSerial.9:LoadBootLoadercodethenwri ... [详细]
  • ABP框架是ASP.NET Boilerplate的简称,它不仅是一个开源且文档丰富的应用程序框架,还提供了一套基于领域驱动设计(DDD)的最佳实践架构模型。本文将详细介绍ABP框架的特点、项目结构及其在Web API优先架构中的应用。 ... [详细]
  • 近年来,区块链技术备受关注,其中比特币(Bitcoin)功不可没。尽管数字货币的概念早在上个世纪就被提出,但直到比特币的诞生,这一概念才真正落地生根。本文将详细探讨比特币、以太坊和超级账本(Hyperledger)的核心技术和应用场景。 ... [详细]
  • Python学习day3网络基础之网络协议篇
    一、互联网协议连接两台计算机之间的Internet实际上就是一系列统一的标准,这些标准称之为互联网协议,互联网的本质就是一系列网络协议。二、为什么要有互联网协议互联网协议就相当于计 ... [详细]
  • 阿里云 Aliplayer高级功能介绍(八):安全播放
    如何保障视频内容的安全,不被盗链、非法下载和传播,阿里云视频点播已经有一套完善的机 ... [详细]
  • 本文详细介绍了 Java 网站开发的相关资源和步骤,包括常用网站、开发环境和框架选择。 ... [详细]
  • 小编给大家分享一下Vue3中如何提高开发效率,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获, ... [详细]
  • 本文整理了关于Sia去中心化存储平台的重要网址和资源,旨在为研究者和用户提供全面的信息支持。 ... [详细]
  • MongoDB核心概念详解
    本文介绍了NoSQL数据库的概念及其应用场景,重点解析了MongoDB的基本特性、数据结构以及常用操作。MongoDB是一个高性能、高可用且易于扩展的文档数据库系统。 ... [详细]
  • 本文详细介绍了 Spark 中的弹性分布式数据集(RDD)及其常见的操作方法,包括 union、intersection、cartesian、subtract、join、cogroup 等转换操作,以及 count、collect、reduce、take、foreach、first、saveAsTextFile 等行动操作。 ... [详细]
author-avatar
mobiledu2502901927
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有