云原生 | .NET 5 with Dapr 初体验

【Dapr总结/Edison Zhou


分布式应用运行时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地址为:。

为所有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<CartController> _logger;private readonly DaprClient _daprClient;public CartController(ILogger<CartController> logger, DaprClient daprClient){_logger = logger;_daprClient = daprClient;}[HttpGet]public async Task<IEnumerable<SKU>> Get(){_logger.LogInformation("[Begin] Query product data from Product Service");var products = await _daprClient.InvokeMethodAsync<IEnumerable<SKU>>(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<SKU> 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<OrderController> _logger;private readonly DaprClient _daprClient;public OrderController(ILogger<OrderController> logger, DaprClient daprClient){_logger = logger;_daprClient = daprClient;}[HttpPost]public async Task<Models.Order> Post(OrderDto orderDto){_logger.LogInformation("[Begin] Create Order.");var order = new Models.Order(){// some mappingId = orderDto.Id,ProductId = orderDto.ProductId,Count = orderDto.Count};// some other logic for ordervar 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.redismetadata:- name: redisHostvalue: localhost:6379- name: redisPasswordvalue: ""

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

apiVersion: dapr.io/v1alpha1
kind: Component
metadata:name: pubsub-rq
spec:type: pubsub.rabbitmqversion: v1metadata:- name: hostvalue: "amqp://localhost:5672"- name: durablevalue: 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》: https://docs.microsoft.com/zh-cn/dotnet/architecture/dapr-for-net-developers

Tony,《Dapr公开课》:https://www.bilibili.com/video/BV1Fb4y197fT

相关文章:

  • Dapr能否引领云原生中间件的未来?

  • 云原生 | 阿里巴巴的Dapr实践与探索

  • Dapr 可视化指南

  • Dapr 知多少 | 分布式应用运行时

  • Dapr 正式发布 1.0

  • Dapr 交通流量控制示例

  • Dapr是如何简化微服务的开发和部署

  • 微软开源微服务运行时Dapr,赋能云原生应用开发

  • Dapr微服务应用开发系列0:概述

  • Dapr微服务应用开发系列1:环境配置

  • Dapr微服务应用开发系列2:Hello World与SDK初接触

  • Dapr微服务应用开发系列3:服务调用构件块

  • Dapr微服务应用开发系列4:状态管理构件块

  • Dapr微服务应用开发系列5:发布订阅构建块

  • Windows环境下Dapr入门

  • 通过Dapr实现一个简单的基于.net的微服务电商系统

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/303263.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python资料分享来袭,收下不谢!

近几年&#xff0c;机器学习一直很火&#xff0c;小编也有意识地收集了机器学习相关的资源&#xff0c;经过长时间的积累和沉淀&#xff0c;内容涵盖“Python教程”、“编程指南”、“学习视频”等。现在&#xff0c;小编准备将这些资料免费分享给大家&#xff01;扫描下面二维…

我敢说,这是最全的常用设计模式汇总

先分享一个小故事两个年轻人是大学同班同学&#xff0c;他们毕业后一起被同一家公司录取&#xff0c;可以说是站在相同的起跑线上。两个人都对未来信心满满&#xff0c;踌躇满志。其中一人怀抱满腔激情&#xff0c;到处学热门框架&#xff0c;但受限于公司体量和业务逻辑&#…

Python为什么是编程语言中最skr的?

源 / 大数据文摘&#xff08;BigDataDigest&#xff09; 编译 / 小七、Virgil、AlieenPython的出现让计算机编程语言不再是生僻的专业技能&#xff0c;而是常人都能学习和使用的万金油。《经济学人&#xff08;Economist&#xff09;》近日对Python的一篇专题报道&#xff0c…

Linux系统管理员的Bash指南,11条Bash实践经验!

每个职业都有最常用的工具。对于许多系统管理员来说&#xff0c;shell可能是比较熟悉的。在大多数Linux和其他类Unix系统上&#xff0c;默认的shell是Bash。Bash是一个相当古老的程序&#xff0c;它起源于20世纪80年代后期。但它建立在更多&#xff0c;更老的shell上&#xff0…

Asp Net Core 5 REST API 使用 RefreshToken 刷新 JWT - Step by Step(三)

翻译自 Mohamad Lawand 2021年1月25日的文章 《Refresh JWT with Refresh Tokens in Asp Net Core 5 Rest API Step by Step》 [1]在本文中&#xff0c;我将向您演示如何在 Asp.Net Core REST API 中将 Refresh Token 添加到 JWT 身份验证。我们将覆盖的一些主题包含&#xff1…

国外的程序猿可以工作到退休而国内的为什么这么短命(思维认知)

首先我想说明的是国外的程序猿也存在加班&#xff0c;他们也要赶项目&#xff0c;所以加班不算什么原因。真正的原因是我们国内的很大一部分程序猿只是工具的使用者&#xff0c;不会去思考工具的产生和原理&#xff0c;用惯了一个高效的工具就被这个工具套牢成为奴隶&#xff0…

使用 docker 部署 mdnice

使用 docker 部署 mdniceIntro最近 mdnice 的在线版使用开始需要登录才能访问&#xff0c;一方面我觉得我的文章会被保存的他们的服务器上&#xff0c;使用他们的平台就能轻松拿到很多文章的数据&#xff0c;他们甚至是可以直接拿到 markdown 原始内容去别的平台分享转发&#…

细数近年来机器学习研究的几大怪现状

人工智能领域的发展离不开学者们的贡献&#xff0c;然而随着研究的进步&#xff0c;越来越多的论文出现了「标题党」、「占坑」、「注水」等现象&#xff0c;暴增的顶会论文接收数量似乎并没有带来更多技术突破。最近&#xff0c;来自卡耐基梅隆大学的助理教授 Zachary C. Lipt…

50K求聘.NET,我们是认真的!

今年的节奏特别快&#xff0c;不知道你有没有同感&#xff1f;春节刚过&#xff0c;跳槽季仓促开始&#xff0c;打了个疫苗&#xff0c;过了个清明&#xff0c;一转头4月过半&#xff0c;金三银四就快尾声了&#xff0c;真是时光飞逝。当然&#xff0c;手速快的已经offer拿到手…

linux编译redis打包,linux下下载redis,并且编译

1&#xff1a;下载、解压、编译$ wget http://download.redis.io/releases/redis-3.0.6.tar.gz$ tar xzf redis-3.0.6.tar.gz$ cd redis-3.0.6$ make2&#xff1a;结果显示很多error&#xff0c;127&#xff0c;1&#xff0c;2之类的&#xff0c;然后我参考了这个网站https://w…

github star破13k,Dapr 能否引领云原生中间件的未来?

Dapr&#xff08;Distributed Application Runtime &#xff0c;分布式应用运行时&#xff09;是微软新推出的&#xff0c;一种可移植的、serverless 的、事件驱动的运行时&#xff0c;它使开发人员可以轻松构建弹性&#xff0c;无状态和有状态微服务&#xff0c;这些服务运行在…

现在的便签本都这么社会了!?重复写万次还能云端保存

不知模友们有没有感觉到每天脑子要记的事情越来越多不说事情杂七杂八重点是精力有限刚说完的事转眼就忘了想过在电脑贴满便利贴想过本子记录好每天要做什么But ......每天忙的天昏地黑啥都不记得了又懒的随身带着本子太重不好携带真想能有一个神器让这一切不再纠结一款神奇又黑…

C#类类型“.NET技术”

类类型是由字段数据&#xff08;成员变量&#xff09;和操作字段数据的成员&#xff08;属性、方法、构造函数、事件等&#xff09;所构成的自定义类型。其中字段数据表示类实例&#xff08;对象&#xff09;的状态。 在C#中&#xff0c;类使用class关键字定义&#xff0c;例如…

linux ext4 格式化工具,ext4格式化软件 mkfs.ext4 快速格式化

如何在 Windows 下访问 ext4 格式的硬盘你好&#xff0c;介绍两个能在 Windows 下读取ext4分区的软件。第一个是 Ext2Read。它能查看 ext2/3/4 分区并从中拷贝文件和目录&#xff0c;支持 LVM2 和 EXT4 extent &#xff0c;以及递归拷贝整个目录。第二个是本站之前介绍过的 Ext…

信心满满的去面算法工程师,竟然凉了...

我是小A&#xff0c;一个没能当成算法工程师的菜鸡Java工程师&#xff0c;内心却等着上AI这趟车。去年正是人工智能火热的时候&#xff0c;看着各种高薪招聘&#xff0c;我沉寂很久的内心也火热起来了。但是想归想&#xff0c;我内心还是有很多纠结的。自己已经很多年没有碰过高…

使用 Redis Stream 实现消息队列

使用 Redis Stream 实现消息队列IntroRedis 5.0 中增加了 Stream 的支持&#xff0c;利用 Stream 我们可以实现可靠的消息队列&#xff0c;并且支持一个消息被多个消费者所消费&#xff0c;可以很好的实现消息队列Simple Usage首先我们来看一个简单版本的 Stream 使用&#xff…

用linux命令通常做什么,如何知道你在 Linux 里最常使用的几个命令?

不知道大家自接触 Linux 以来&#xff0c;都使用过哪些命令&#xff0c;其中最常用的命令是什么&#xff1f;我最常用的命令之一是 sudo &#xff0c;因为我每天都在使用它在 Linux 上安装、更新、删除软件包以及其它各种需要超级用户权限的操作。那么你知道你自己最经常使用的…

资料分享 | python机器学习教程分享来袭

小天从大学开始&#xff0c;便开启资料收集功能。近几年以AlphaGo为契机&#xff0c;人工智能进入新的发展阶段&#xff0c;再加上日常的深入研究&#xff0c;小天收集整理了丰富的机器学习资料&#xff0c;内容涵盖“机器学习视频”&#xff0c;“机器学习教程”等。截止到今天…

Autofac框架初识与应用

一、前言这上一篇中&#xff0c;主要讲述了什么是IoC容器&#xff0c;以及了解到它是DI构造函注入的框架&#xff0c;它管理着依赖项的生命周期以及映射关系&#xff0c;同时也介绍实践了在ASP.Net Core中,默认提供的内置IoC容器&#xff0c;以及它的实例注册方式和相应的生命周…

聊一聊数据导出那些事

前言 数据导出&#xff0c;这可以说是一个随处可见的需求&#xff0c;大部分管理平台&#xff0c;报表系统都会有这个需求。对于这个需求&#xff0c;不少系统会做限制&#xff0c;只能从系统导出几千或几万的数据&#xff0c;再多的话就要提申请&#xff0c;经过层层审批&…