通过Dapr实现一个简单的基于.net的微服务电商系统(二)——通讯框架讲解
首先感谢张队@geffzhang公众号转发了上一篇文章,希望广大.neter多多推广dapr,让云原生更快更好的在.net这片土地上落地生根。
目录:
一、通过Dapr实现一个简单的基于.net的微服务电商系统
二、通过Dapr实现一个简单的基于.net的微服务电商系统(二)——通讯框架讲解
三、通过Dapr实现一个简单的基于.net的微服务电商系统(三)——一步一步教你如何撸Dapr
四、通过Dapr实现一个简单的基于.net的微服务电商系统(四)——一步一步教你如何撸Dapr之订阅发布
附录:(如果你觉得对你有用,请给个star)
一、电商Demo地址
书接上回,今天来分享一下这套电商demo的通讯部分到底是如何工作的,看看它是如何屏蔽与dapr繁琐的沟通工作让开发者专注于解决业务问题的。
首先我们再回顾一下dapr的sidecar是如何与应用相互协同的。和istio类似,dapr的sidecar注入可以分为自动注册和手动注册,下面以手动加注解注册的方式我们来聊一聊dapr的工作逻辑。首先当我们设置一个应用(deployment)的时候,在template-metadata配置了dapr相关注解之后,凡是安装dapr集群的k8s会自动将dapr的sidecar注册到我们的pod中,如下图:
当服务启动后,我们可以用kubectl describe po xxx的方式看到当前该pod会产生两个容器:
凡是了解k8s的开发人员应该知道。在同一个pod之中,container实例之间的通讯应该是基于同一个虚拟内网的,通俗的说就是两者通讯可以直接通过localhost:port的方式,这是dapr与应用交互的基础。和istio通过iptables 来做流量劫持让Envoy代理可以拦截所有的进出Pod的流量,即将入站流量重定向到 Sidecar,再拦截应用容器的出站流量经过 Sidecar 处理的方案相比,dapr选择了一个更加灵活的方式,也就是它只是主动暴露一个端口(默认3500),将是否和dapr通讯的选择权留给了应用本身。
当我们发起一个rpc请求时,实际上我们是通过http(or grpc这里不展开)的方式,访问了了http://localhost:3500/v1.0/{invoke}/{servicename}/method/{path} 这么一个地址。sidecar通过解析这个地址得到远程服务名{servicename},以及一个谓词{invoke}以及远程服务的endpoint:{path}。它会通过内部的dns服务名查询servicename得到一个该服务在集群内的实例列表,通过负载均衡的方式发起一个下游调用。这个下游调用也并非直接像普通k8s应用内通过调用service name的方式去调用下游pod的container,而是访问下游pod内的sidecar,通过sidecar再去访问pod内的应用实例。他们之间的调用关系如图所示:
通过这样的设计,实际上应用只需要和daprd这个sidcar打交道即可。同时dapr实现了通过谓词解析成不同的服务类型实现。比如服务间调用通过谓词:{invoke}、状态读写的谓词是{state}、订阅发布的谓词是{publish}、{subscribe},几乎所有的行为都可以分解成谓词+服务名+endpoint这种模式(所有api可参考:https://docs.dapr.io/reference/api/),这也是实现这套通讯框架的基础。
所以剩下的事情就比较简单了,dapr通讯基于http/grpc,所以我们只需要启动一套kestrel+httpclient or grpc service/client即可简单快捷的接入dapr。首先我们还是看看整个repo(https://github.com/sd797994/Oxygen-Dapr)的结构:
Oxygen这部分主要是包含通用工具层、IOC依赖注入(基于autofac)、本地代理生成器ProxyGenerator。Client主要包含一些远程服务attr标记以及客户端代理工厂。而在Mesh这个单独分层里主要是对Dapr的Actor实现了相关封装、Service层比较简单,只是在hostbuilder启动了一个kestrel并获取所有标记了远程服务的接口来构建路由字典方便将我们的Application服务暴露成restapi。
本地代理ProxyGenerator实现比较简单,使用了微软自带的代理类DispatchProxy。通过Autofac依赖注入接口的时候将接口和代理类实现注册到ioc容器中,这样当我们通过IServiceProxyFactory.CreateProxy时实际上是从ioc容器中拿到的DispatchProxy实例,这样调用任意该接口的方法都会被路由到DispatchProxy实例,从而实现方法拦截并最终通过RemoteMessageSender类型里的HttpClient发起对dapr的sidecar请求。
Client层的ServerProxyFactory也比较简单,其实就三个东西,一个是IServiceProxyFactory,这个主要用于发起对远程rpc和actor的调用、一个是IEventBus以及IStateManager,分别用于发布事件和调用dapr的状态管理器。
Service.Kestrel层主要是通过启动时由RequestDelegateFactory.CreateDelegate的方式将所有注册为remoteservice的接口实现为其构造一个Func<Tservice, Tin, Task<Tout>>这样的匿名委托并将其路由键和该委托注册到一个全局静态字典中。当收到请求时通过kv键值对的方式查询当前key(router)对应的匿名委托,并通过ioc容器构造一个Tservice实例(为什么要请求时创建一个实例?因为这样可以模拟MVC创建controller的方式将Tservice作为一个scope生命周期的对象创建出来,避免Tservice内部的构造函数依赖的非单例对象生命周期失效)
整个请求收发流程如下:
1、当客户端通过IServiceProxyFactory.CreateProxy<IxxxServcice>()时获取到该接口的DispatchProxy实例。
2、实例解析各种参数后发起一个http调用,http请求localhost:3500的sidecar后等待回调。
3、sidecar将请求组装后发给下游sidecar并由下游sidecar转发给pod内的应用。
4、应用收到请求后解析path得到对应的RequestDelegate,调用RequestDelegate将请求打到具体的xxxServcice服务上,由服务完成具体的业务。
Mesh.Dapr则是对Actor行为的一个具体封装,由于原始的dapr sdk需要继承BasicActor然后进行各种actor作业,我采用了另外一种方式,通过emit静态代理的方式创建了一个Actor服务,由其代为接收actor请求后再转发给具体的xxxServcice。同时这个Actor服务会启动一个timer,当timer到期时会进行一次model的版本检查,当版本变化后(一般是由于xxxServcice被调用),会通知xxxServcice继承自基类并重写的SaveData方法,由xxxServcice自身考虑是否需要做业务层的持久化(默认Actor代理服务会自动持久化到dapr的状态设备里),这一步是完全异步的并不会阻塞Actor代理原方法的执行,另外在Actor的使用中,我们也尽量避免在同步调用时去读取第三方的设备可能导致IO阻塞actor。在源码中涉及对actor调用xxxServcice异步的支持,我主要参考了async/await生成状态机的方式创建了一个ActorAsyncStateMachine,由该状态机来完成actor服务调用xxxServcice的async/await实现。
sample包含一对客户端/服务端案例包含上述涉及的所有远程call,大家可以多参考一下。
Dapr原始提供了一套sdk用于远程服务,该框架主要是用于实现rpc以及对dapr这些api的自定义封装,当使用这套框架后我们就可以不用再考虑创建具体的webapi控制器,由iapplicationservice申明远程服务后框架即可自动生成代理服务即可。
该框架的实现方式当然还有诸多不完善或者我没考虑到的地方,主要起到一个抛砖引玉的作用,另外也是通过这个来了解dapr是如何统一了我们网络编程模型的,只有更了解dapr才能更好的使用和推广它。惯例,欢迎fork+star:
https://github.com/sd797994/Oxygen-Dapr
https://github.com/sd797994/Oxygen-Dapr.EshopSample
通过Dapr实现一个简单的基于.net的微服务电商系统(二)——通讯框架讲解的更多相关文章
- 通过Dapr实现一个简单的基于.net的微服务电商系统(二十)——Saga框架实现思路分享
今天这篇博文的主要目的是分享一下我设计Saga的实现思路来抛砖引玉,其实Saga本身非常的类似于一个简单的工作流体系,相比工作流不一样的部分在于它没有工作流的复杂逻辑处理机制(比如会签),没有条件分支 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(四)——一步一步教你如何撸Dapr之订阅发布
之前的章节我们介绍了如何通过dapr发起一个服务调用,相信看过前几章的小伙伴已经对dapr有一个基本的了解了,今天我们来聊一聊dapr的另外一个功能--订阅发布 目录:一.通过Dapr实现一个简单的基 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统
本来想在Dpar 1.0GA时发布这篇文章,由于其他事情耽搁了放到现在.时下微服务和云原生技术如何如荼,微软也不甘示弱的和阿里一起适时推出了Dapr(https://dapr.io/),园子里关于da ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(三)——一步一步教你如何撸Dapr
目录:一.通过Dapr实现一个简单的基于.net的微服务电商系统 二.通过Dapr实现一个简单的基于.net的微服务电商系统(二)--通讯框架讲解 三.通过Dapr实现一个简单的基于.net的微服务电 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(五)——一步一步教你如何撸Dapr之状态管理
状态管理和上一章的订阅发布都算是Dapr相较于其他服务网格框架来讲提供的比较特异性的内容,今天我们来讲讲状态管理. 目录:一.通过Dapr实现一个简单的基于.net的微服务电商系统 二.通过Dapr实 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(六)——一步一步教你如何撸Dapr之Actor服务
我个人认为Actor应该是Dapr里比较重头的部分也是Dapr一直在讲的所谓"stateful applications"真正具体的一个实现(个人认为),上一章讲到有状态服务可能很 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(七)——一步一步教你如何撸Dapr之服务限流
在一般的互联网应用中限流是一个比较常见的场景,也有很多常见的方式可以实现对应用的限流比如通过令牌桶通过滑动窗口等等方式都可以实现,也可以在整个请求流程中进行限流比如客户端限流就是在客户端通过随机数直接 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(八)——一步一步教你如何撸Dapr之链路追踪
Dapr提供了一些开箱即用的分布式链路追踪解决方案,今天我们来讲一讲如何通过dapr的configuration来实现非侵入式链路追踪的 目录:一.通过Dapr实现一个简单的基于.net的微服务电商系 ...
- 通过Dapr实现一个简单的基于.net的微服务电商系统(九)——一步一步教你如何撸Dapr之OAuth2授权
Oauth2授权,熟悉微信开发的同学对这个东西应该不陌生吧.当我们的应用系统需要集成第三方授权时一般都会做oauth集成,今天就来看看在Dapr的语境下我们如何仅通过配置无需修改应用程序的方式让第三方 ...
随机推荐
- JDK源码阅读-FileInputStream
本文转载自JDK源码阅读-FileInputStream 导语 FileIntputStream用于打开一个文件并获取输入流. 打开文件 我们来看看FileIntputStream打开文件时,做了什么 ...
- Error running 'tomcat': Unknown error
免费分享95套java实战项目,不仅有源码还有对应的开发视频,关注公众号『勾玉技术』回复"95"即可获取 无意中发现了一位清华大佬的算法笔记,需要的加公众号 勾玉技术 回复 清华算 ...
- 【Azure 服务总线】Azure Service Bus中私信(DLQ - Dead Letter Queue)如何快速清理
在博文ServiceBus 队列中死信(DLQ - Dead Letter Queue)问题一文中,介绍了服务总线产生私信的原因及可以通过代码的方式来清楚私信队列中的消息,避免长期占用空间(因为私信中 ...
- Java 面向对象 04
面向对象·四级 多态的概述及其代码实现 * A:多态(polymorphic)概述 * 事物存在的多种形态 * B:多态前提 * a:要有继承关系 * b:要有方法重写 * c: 要有父类引用指向子类 ...
- 在scanf函数中占位符使用错误而产生的一些错误
出现的问题 在做编程题的的时候,遇到了一个很奇怪的错误,出问题的代码如下: 1 #include <cstdio> 2 using namespace std; 3 4 int main( ...
- Mark一个代码量统计工具-Statistic
安装方式 IDEA.Goland系列插件市场搜索Statistic 简单说明 统计纬度比较丰富 基本覆盖常见纬度,如代码行数,文件大小等,各指标取最大最小及平均值. 统计目录为当前项目目录 只有在当前 ...
- LNMP配置——Nginx配置 ——域名重定向
一.配置 #vi /usr/local/nginx/conf/vhost/test.com.conf 写入: server { listen 80; server_name test.com test ...
- Less常用变量与方法记录
需求:仅记录Lsee常用变量与方法定义,便于使用.-- @color: #000; @title-color: #000; @bg-color: #fff; @small-font: 12px; @l ...
- 【odoo14】第四章、应用模型
由于本章有包含很多基础知识,个人不会全部转化为自己的语言.直接机器翻译了(用斜体标注,机器翻译反而一字不落,我会过滤掉冗余的内容),虽然机翻,但会保证意思不会偏. 本章主要章节如下: 定义模型展示及顺 ...
- Django之模版层
一.模版简介 你可能已经注意到我们在例子视图中返回文本的方式有点特别,也就是说,HTML被直接硬编码在python代码之中. def current_datetime(request): now = ...