云原生 | .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,一经查实,立即删除!

相关文章

linux中的ip地址范围,linux – ip地址范围参数

从http://linux-ip.net/html/tools-ip-address.html&#xff1a;Scope | Descriptionglobal | valid everywheresite | valid only within this site (IPv6)link | valid only on this devicehost | valid only inside this host (machine)范围通常由ip实用程序确定,无需在命令…

充分利用系统的组策略 保障共享目录安全

在日常的办公应用中&#xff0c;为了使用的方便&#xff0c;我们习惯于将自己电脑上的一些文档、目录共享出来&#xff0c;以便于别人调用。但是对于共享的文件夹常常无法做到在使用后即将其关闭&#xff0c;这样网络上一些别有用心的人则可能对我们的共享文件进行破坏&#xf…

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…

微软:Vista SP2是最安全的操作系统

微软首席运行官Kevin Turner在上周末的Midmarket CIO峰会上表示&#xff0c;Windows Vista SP2是最安全的一款操作系统&#xff0c;它在安全性能方面比开源Linux和苹果的Mac OS X Leopard都要出色&#xff0c;不过除了这一观点外&#xff0c;Turner并没有详谈Vista SP2的安全措…

linux mysql帮助文档,在 Linux 上安装 MySQL

## 2.5 在 Linux 上安装 MySQLLinux 支持多种不同的 Linux 安装解决方案. We recommend that you use one of the distributions from Oracle, for which several methods for installation are available:**表 2.7 Linux 安装方法和信息**| 类型 | 设置方法 | 附加信息 ||:---…

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…

java.net.sockettimeoutexception read timed out

java.net.sockettimeoutexception read timed out超时时间设长一点儿即可Socket.setSoTimeout(int timeout); ----------------------------------------------------------------------------------------------------------------------------------------------------------…

linux把终端嵌入桌面,在Ubuntu Linux桌面上嵌入终端窗口

除了Tilda 和 Yakuake 终端具有嵌入桌面的效果之外&#xff0c;使用 Devil’s Pie 这个小程序你同样可以将终端窗口嵌入到你的 Linux 桌面。下面就以 GNOME Terminal 为例来说明嵌入到桌面的过程&#xff1a;1、安装 Devil’s Pie&#xff1a;在 Debian/Ubuntu 中可以通过执行下…

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

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

使用 docker 部署 mdnice

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

59、crontab用法简介

1、格式 minute hour day month dayofweek command 2、示例 1&#xff09;12 3 * * * root tar czf /usr/local/backups/daily/etc.tar.gz /etc >> /dev/null 2>&1 在每天凌晨3点12分&#xff08;03:12&#xff09;运行该语句&#xff1b; tar czf /usr/local/bac…

国内linux内核镜像仓库,国内较快的maven仓库镜像

国内连接maven官方的仓库更新依赖库&#xff0c;网速一般很慢&#xff0c;收集一些国内快速的maven仓库镜像以备用。国内OSChina提供的镜像&#xff0c;非常不错CNOSChina Centralhttp://maven.oschina.net/content/groups/public/centralOSChina Maven 库使用帮助其他maven仓库…

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

人工智能领域的发展离不开学者们的贡献&#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 ......每天忙的天昏地黑啥都不记得了又懒的随身带着本子太重不好携带真想能有一个神器让这一切不再纠结一款神奇又黑…