- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章从零开始使用Dapr简化微服务的示例由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
现有的微服务模式需要再业务代码中集成大量基础设施模块,比如注册中心,服务发现,服务调用链路追踪,请求熔断,重试限流等等,使得系统过于臃肿重量级.
Dapr作为新一代微服务模式,使用sidecar模式,简化了现有微服务系统代码,将基础设施层以sidecar模式分离,使得开发人员更集中于业务逻辑编写.
本文以net6和dapr1.5为基础,搭建一个dapr的简单使用示例.
Dapr的运行依赖于Docker环境.
作为学习环境,使用Centos 7系统安装Docker.
安装Docker推荐使用daocloud一键安装命令:
1
|
curl -sSL https:
//get
.daocloud.io
/docker
| sh
|
安装完成后运行命令:
1
2
|
[root@localhost ~]
# docker -v
Docker version 20.10.11, build dea9396
|
显示对应的Docker版本即安装成功.
官方解释:Dapr CLI 是您用于各种 Dapr 相关任务的主要工具。 您可以使用它来运行一个带有Dapr sidecar的应用程序, 以及查看sidecar日志、列出运行中的服务、运行 Dapr 仪表板.
下载Dapr CLI 。
1
|
wget -q https:
//raw
.githubusercontent.com
/dapr/cli/master/install/install
.sh -O - |
/bin/bash
|
验证安装情况 。
1
|
dapr -
v
|
输出以下内容即安装成功.
1
2
|
CLI version: 1.5.0
Runtime version: 1.5.0
|
由于国内网络问题,使用官方的Dapr安装方法一般会遇到各种问题,因此把dapr下载下来,通过脚本进行安装.
修改hosts文件 。
1
2
3
4
|
vi
/etc/hosts
140.82.114.4 github.com
199.232.69.194 github.global.ssl.fastly.net
140.82.114.9 codeload.github.com
|
刷新缓存 。
1
2
|
yum
install
-y nscd
service nscd restart
|
首先需要安装Git,然后执行以下命令:
1
2
3
|
git clone -
v
https:
//gitee
.com
/Two-Twoone/dapr-installer
.git
cd
dapr-installer/
.
/install
.sh
|
虽然还是很慢,但是总比下不了好多了.
上面命令启动了几个容器,运行下列操作来验证:
1
2
3
4
5
|
[root@localhost dapr-installer]
# docker ps --format "table {{.ID}}\t{{.Names}}\t{{.Ports}}"
CONTAINER ID NAMES PORTS
a0565f609846 dapr_placement 0.0.0.0:50005->50005
/tcp
, :::50005->50005
/tcp
c392f5cf7a18 dapr_redis 0.0.0.0:6379->6379
/tcp
, :::6379->6379
/tcp
2ee68c450b29 dapr_zipkin 9410
/tcp
, 0.0.0.0:9411->9411
/tcp
, :::9411->9411
/tcp
|
1
2
3
|
rpm -Uvh https:
//packages
.microsoft.com
/config/rhel/7/packages-microsoft-prod
.rpm
yum update
yum
install
dotnet-sdk-6.0
|
创建2个项目分别为 product,cart 引用Dapr 。
1
|
dotnet add package Dapr.AspNetCore
|
Program.cs中对 的 AddDapr 调用将 DaprClient 类注册到 ASP.NET Core注入系统。 注册客户端后,现在可以将 的实例注入服务代码, DaprClient 以与 Dapr sidecar、构建基块和组件进行通信.
1
|
builder.Services.AddControllers().AddDapr();
|
在微服务系统中,服务与服务间的调用必不可少,难点主要集中在服务所在位置,发生错误时如何重试,负载均衡等问题.
Dapr中使用sidecar 作为服务的反向代理模块来解决这些问题.
prodcut项目增加下列代码 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
[Route("api/[controller]")]
[ApiController]
public class ProductController : ControllerBase
{
private ILogger<ProductController> _logger;
public ProductController(ILogger<ProductController> logger)
{
_logger = logger;
}
private static readonly List<string> products = new List<string> { "aa", "bb", "cc", "dd", "ee", "ff", "gg", "hh", "ii", "jj", "kk", "ll", "mm", "nn" };
[HttpGet]
public ActionResult Get()
{
_logger.LogInformation($"调用了获取商品方法");
string[] temps = new string[5];
for (int i = 0; i < 5; i++)
{
Random random = new Random(Guid.NewGuid().GetHashCode());
temps[i] = products[random.Next(0, products.Count - 1)];
}
return Ok( temps);
}
}
|
1
2
|
# 启动Product 项目
dapr run --app-
id
ProductDemo --app-port 5010 --dapr-http-port 7015 -- dotnet
/root/www/product/Dapr
.Product.Sample.dll --urls <a rel=
"external nofollow"
href=
"http://*:5010/"
>http:
//
*:5010<
/a
>
|
cart项目增加下列代码,dapr支持http,grpc调用方式,这里以常用的webapi为例,使用http方式调用.
InvokeMethodAsync方法中appid对应的就是dapr run 中的appid,无需关系调用地址.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
[Route("api/[controller]")]
[ApiController]
public class CartController : ControllerBase
{
private readonly DaprClient _daprClient;
private readonly ILogger<CartController> _logger;
public CartController(DaprClient daprClient, ILogger<CartController> logger)
{
_daprClient = daprClient;
_logger = logger;
}
[HttpGet]
[Route("GetProducts")]
public async Task<IActionResult> GetProducts()
{
_logger.LogInformation($" Cart 获取商品");
var products = await _daprClient.InvokeMethodAsync<List<string>>(HttpMethod.Get, "ProductDemo", "/api/Product/GetAll");
return Ok(products);
}
}
|
将程序上传到linux服务器,运行程序 。
1
2
|
# 启动 Cart 项目
dapr run --app-
id
CartDemo --app-port 5020 --dapr-http-port 7025 -- dotnet
/root/www/cart/Dapr
.Cart.Sample.dll --urls <a rel=
"external nofollow"
href=
"http://*:5020/"
>http:
//
*:5020<
/a
>
|
调用接口,可以看到Cart项目几乎没有代码入侵就实现了接口调用.
1
2
|
[root@localhost ~]
# curl -X 'GET' 'http://192.168.2.110:5020/api/Cart/GetProducts'
[
"aa"
,
"bb"
,
"cc"
,
"dd"
,
"ee"
,
"ff"
,
"gg"
,
"hh"
,
"ii"
,
"jj"
,
"kk"
,
"ll"
,
"mm"
,
"nn"
]
|
Dapr内部使用了mDns进行了服务注册发现和负载均衡,部署多个product后调用,可以看到轮询调用效果.
在自承载模式下,Dapr 使用 mDNS 查找它。在 Kubernetes 模式下运行时,Kubernetes DNS 服务确定地址.
在调用失败和瞬态错误的情况下,服务调用会执行自动重试,Dapr 默认是开启了重试,所以接口不支持幂等是十分危险的行为.
发布订阅模式,主要是用于微服务间基于消息进行相互通信。你可能也会说,这也要拿出来说,我搞个RabbitMQ/Kafka就是了, 。
原来我们都会根据使用的组件引入不同的sdk,不同的消息队列监听、消费模式还不一样.
Dapr 提供了一个构建基块,可显著简化实现发布/订阅功能,从而和底层基础设施解耦,编写业务逻辑时不需要关心是什么消息队列.
再Program中添加发布订阅支持 。
1
2
3
4
5
|
app.UseCloudEvents();
app.UseEndpoints(endpoints =>
{
endpoints.MapSubscribeHandler();
});
|
订阅消息,使用Topic特性,传递pubsub和主题名称 。
1
2
3
4
5
6
|
[Topic("pubsub", "newUser")]
public ActionResult subUserInfo(UserInfo us)
{
_logger.LogInformation($"接收到订阅消息 id:{us.id} name:{us.name},age:{us.age},sex:{us.sex}");
return Ok("处理完毕");
}
|
发布消息,使用dapr公开方法PublishEventAsync,传递pubsub和主题名称,以及消息体 。
1
2
3
4
5
6
|
[HttpPost]
public async Task<IActionResult> PubUserInfo(UserInfo us)
{
await _daprClient.PublishEventAsync("pubsub", "newUser", us);
return Ok();
}
|
消息发布订阅组件支持RabbitMQ,Redis,Kafka等.
Dapr 默认使用 Redis 作为状态存储。它也支持MongoDB,PostgreSQL,SQL Server等.
它不会对上层暴露底层用的那个中间件,也就是说在不同环境下可以使用同一套代码来使用不同的中间件.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
[HttpPost]
[Route("SaveUserList")]
public async Task<IActionResult> SaveUserList()
{
var temps = new List<UserInfo>
{
new UserInfo("小红",1,true,Guid.NewGuid().ToString()),
new UserInfo("小黄",1,true,Guid.NewGuid().ToString()),
new UserInfo("小蓝",1,true,Guid.NewGuid().ToString())
};
await _daprClient.SaveStateAsync("statestore", "UserList", temps);
return Ok(1);
}
[HttpGet]
[Route("GetUserList")]
public async Task<IActionResult> GetUserList()
{
var list = await _daprClient.GetStateAsync<List<UserInfo>>("statestore", "UserList");
return Ok(list);
}
[HttpGet]
[Route("DeleteUserList")]
public async Task<IActionResult> DeleteUserList()
{
await _daprClient.DeleteStateAsync("statestore", "UserList");
return Ok(1);
}
public record UserInfo(string name, int age, bool sex, string id);
|
传统微服务中,要实现链路追踪,对代码的侵入强.
Dapr 在 Sidecar 中添加了一个 http/grpc中间件。拦截所有应用程序流量,并自动注入关联 ID 以跟踪分布式事务.
使用 Zipkin 协议进行分布式跟踪,无需代码检测,使用可配置的跟踪级别自动跟踪所有流量.
。
本文只是对Dapr做了一个简单示例,对各个组件具体的实现原理没有做过多深入讲解.
Dapr区别于传统微服务框架最大的优点就是Sidecar 。以前的微服务框架都需要代码项目引用微服务相关的一些类库,无论是服务注册发现、熔断、配置等都是要调用对应类库实现,这些类库是运行在微服务的进程中的,因此这些类库都需要使用和业务代码一样(或者兼容)的语言来开发,因此是比较重的.
而Sidecar 这种模式,把“注册发现、熔断、配置”等这些微服务的功能都剥离到一个和业务代码的进程相伴而行的独立进程中,业务代码通过http或者grpc等方式和这个Sidecar 进程通讯来完成微服务的相关服务的调用.
显而易见,在Sidecar 这种模式中,业务代码中只有极少数和Sidecar 进程通讯的代码,因此非常轻量级。这样Sidecar 进程中的服务可以独立升级,模块可以自由组合,不会干扰业务代码。同时由于Sidecar 的进程是独立的进程,业务代码和Sidecar 进程通讯是采用http、grpc这样语言无关的协议,因此业务代码可以采用任何语言来进行开发.
到此这篇关于从零开始使用Dapr简化微服务的文章就介绍到这了,更多相关Dapr简化微服务内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://www.cnblogs.com/fulu/p/15607750.html 。
最后此篇关于从零开始使用Dapr简化微服务的示例的文章就讲到这里了,如果你想了解更多关于从零开始使用Dapr简化微服务的示例的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
hello1 hello2 hello3 hello4 hello5 hello6
有没有更简短的写法: (apply f (cons a (cons b (cons c d)))) ? 谢谢! (我正在编写一些调用其他函数的辅助函数,这种“模式”似乎经常出现
.NET团队北京时间2024年5月22日已正式发布.NET Aspire ,在博客文章里做了详细的介绍:.NET Aspire 正式发布:简化 .NET 云原生开发 - .NET 博客 (micros
在this dbfiddle demo我有一个 DELETE FROM...WHERE 最后像这样: ...... DELETE FROM data_table WHERE
我有几个 if 语句,如下面的一个。我假设这是一种非常糟糕/长期的编码方式,但不确定我应该做些什么不同的事情。有人有什么建议吗? 谢谢 For a = 1 To Leagues If a =
有什么类似的战术simpl为 Program Fixpoint ? 特别是,如何证明以下无关紧要的陈述? Program Fixpoint bla (n:nat) {measure n} := mat
我使用此代码来跟踪表单上是否有任何更改: $(document).on('input', '.track', function() { var form = $(this); }); 由于这不
我有以下函数,我想用 for 循环来简化它,但不知道该怎么做。任何帮助都感激不尽。基本上,如果字段值为 0 或 null,则我的总值(字段)应为 0,否则,如果字段值从 1 到 1000,则总值变为
我正在尝试对时间字符串执行非常简单的解析 data Time = Time Int Int Int String -- example input: 07:00:00AM timeParser ::
为了使我的代码更具可读性和更简单,我对这段代码绞尽脑汁: var refresh = setInterval(datumTijd, 1000); function datumTijd() { do
这个问题已经有答案了: Check if a variable is in an ad-hoc list of values (8 个回答) 已关闭 9 年前。 只是一个基本的if声明,试图使其更简单
我有一个这样的 if 语句 int val = 1; if (val == 0 || val == 1 || val == 2 || ...); 有没有更简单的方法?例如: int val = 1;
我有一个程序,其中有一些 if 语句,与我将要向您展示的程序类似。我想知道你们是否可以帮助我以任何方式简化这个方程。我之所以问这个问题,是因为在我的 Notepad++ 中,它持续了 443 列,如果
是否可以简化这个 if 语句? 如果是,答案是什么? if (type) { if(NdotL >= 0.0) { color
我有一个包含亚马逊大河的 shapefile。仅 shapefile 就有 37.9 MB,连同属性表高达 42.1 MB。我正在生成所有巴西亚马逊的 PNG 图像,每个 1260x940 像素,sh
System.out.printf("%7s", "a"); System.out.printf("%7s", "b"); System.out.printf("%7s", "c"); S
假设我们有客户端-服务器应用程序,由一个 makefile 编译。服务器使用 libtask 为并行客户端提供服务。客户端使用 ncurses 来处理某些图形。目录树如下所示: ./ --bin/ -
我在 Mono 密码转换的重新实现中找到了这段代码。 我没有修改或简化任何东西 - 这就是它的实际运行方式(有评论如//Dispose unmanaged objects,但实际上什么也没做)。 现在
我需要一些帮助来简化这个包含数百行的庞大代码,但我真的不知道该怎么做。代码看起来真的很乱,我需要的是返回具有预定义文本颜色的模型。有什么简单的方法吗? 我必须多解释一点:- 有一个包含许多型号的手机列
这里有一些代码可以正常工作,但我认为可以简化/缩短。它基本上是点击一个列表项,获取它的 ID,然后根据 ID 显示/隐藏/删除元素。 关于如何使用函数或循环来简化它的建议? $("#btn_remov
我是一名优秀的程序员,十分优秀!