**
**
官方解释:Dapr (Distributed Application Runtime)是一个可移植的、事件驱动的运行时
目前微服务架构面临哪些问题
服务注册与发现
链路追踪
服务降级,熔断,限流,重试
服务网关
……
在设计微服务应用时,需要考虑很多因素。 Dapr提供了一些常用功能的最佳实践,开发人员可以使用标准模式进行微服务应用的构建,并部署到任意环境中。 Dapr 通过提供分布式构建块来实现此目的。
每个构建块都是独立的,这意味着您可以采用其中一个、多个或全部来构建应用。 目前,可用的构建块如下:
4.1 服务的调用
4.1.1 介绍
通过服务调用,应用程序可以使用 gRPC 或 HTTP 这样的标准协议来发现并可靠地与其他应用程序通信。
在许多具有多个需要相互通信的服务的环境中,开发者经常会问自己以下问题:
4.1.3 特征
提供不同调用方式
4.2 状态管理
4.2.1 介绍
状态管理是任何应用程序最常见的需求之一:无论是新是旧,是单体还是微服务。 与不同的数据库库打交道,进行测试,处理重试和故障是很费时费力的。
Dapr提供的状态管理功能包括一致性和并发选项。 在本指南中,我们将从基础知识开始。使用键/值状态API来允许应用程序保存,获取和删除状态。
4.2.2 如何存储
你的应用程序可以使用Dapr的状态管理API,使用状态存储组件保存和读取键/值对,如下图所示。 例如,通过使用HTTP POST可以保存键/值对,通过使用HTTP GET可以读取一个键并返回它的值。
4.2.3 特征
可插拔状态存储
Dapr数据存储被建模为组件,可以在不修改你的服务代码的情况下进行替换。 See supported state stores to see the list.
可配置的状态存储行为
Dapr允许开发人员在对于状态的操作请求中附加额外的元数据,这些元数据用以描述期望如何处理该请求。 你可以附加以下:
Note on ETags
对于原生不支持ETags的存储引擎,要求相应的Dapr状态存储实现能够模拟ETags,并在处理状态时遵循Dapr状态管理API规范。 由于Dapr状态存储实现在技术上是底层数据存储引擎的客户端,所以这种模拟应该直接使用存储引擎提供的并发控制机制。
一致性
Dapr同时支持强一致性和最终一致性,其中最终一致性为默认行为。
当使用强一致性时,Dapr会等待所有副本(或指定的quorums)确认后才会确认写入请求。 当最终使用一致性时,Dapr 将在基本数据存储接受写入请求后立即返回,即使这是单个副本。
Read the API reference to learn how to set consistency options.
批量操作
Dapr 支持两种类型的批量操作 - bulk 或 multi。 您可以将几个相同类型的请求分组成批量(或批次)。 Dapr将请求作为单个请求批量提交给基础数据存储。 换句话说,批量(bulk)操作不是事务性的。 另一方面,您可以将不同类型的请求分组为多操作,作为原子事务处理。
4.3 发布和订阅概述
4.3.1 介绍
发布 / 订阅模式 允许微服务使用消息相互通信。 生产者或发布者 将消息发送至 主题(Topic) ,并且不知道接收消息的应用程序。 这涉及将它们写入一个输入频道。 同样,一个 消费者 将订阅该主题并收到它的消息,并且不知道什么应用程序生产了这些消息。 这涉及从输出频道接收消息。 中间消息代理(intermediary message broker)负责将每条消息从输入频道复制到所有对此消息感兴趣的订阅者的输出频道。 当您需要将微服务解偶时,此模式特别有用。
Dapr 中的发布/订阅 API 提供至少一次(at-least-once)的保证,并与各种消息代理和队列系统集成。 您的服务所使用的特定实现是可插入的,并被配置为运行时的 Dapr Pub/Sub 组件。 这种方法消除了您服务的依赖性,从而使您的服务可以更便携,更灵活地适应更改。
当客户端调用具有特定标识的 actor ( 例如,actor Id 123) 时,客户端的 Dapr 实例将散列 actor 类型和 Id,并使用该信息来调用相应的 Dapr 实例,该实例可以为该特定 actor Id提供请求。 因此,始终对任何给定 actor Id 始终会落在同一分区 (或服务实例) 。 如下图所示。
这简化了一些选择,但也带有一些考虑:
POST/GET/PUT/DELETE http://localhost:3500/v1.0/actors/<actorType>/<actorId>/<method/state/timers/reminders>
您可以在请求主体中为 actor 方法提供任何数据,并且请求的响应在响应主体中,这是来自 actor 方法调用的数据。
Refer to Dapr Actor Features for more details.
4.5.5.1 并发(Concurrency)
Dapr Actors 运行时提供了一个简单的基于回合的访问模型,用于访问 Actors 方法。 这意味着任何时候都不能有一个以上的线程在一个 actor 对象的代码内活动。 基于回合的访问大大简化了并发系统,因为不需要同步数据访问机制。 这也意味着系统的设计必须考虑到每个 actor 实例的单线程访问性质。
单个 actor 实例一次无法处理多个请求。 如果 actor 实例预期要处理并发请求,可能会导致吞吐量瓶颈。
如果两个 Actors 之间存在循环请求,而外部请求同时向其中一个 Actors 发出外部请求,那么 Actors 可以相互死锁。 Dapr actor 运行时会自动分出 actor 调用,并向调用方引发异常以中断可能死锁的情况。
4.5.5.2基于回合的访问
一个回合包括执行 actor 方法以响应来自其他 Actors 或客户端的请求,或执行 timer/reminders 回调。 即使这些方法和回调是异步的,但 Dapr Actors 运行时并没有将它们交错(Interleave ,即并发调用它们)。 在允许新回合之前,必须完全结束之前的回合。 换句话说,在允许对方法或回调进行新调用之前,必须完全完成当前正在执行的 actor 方法或 timer/reminders 回调。 如果执行从方法或回调返回结果,并且方法或回调返回的任务已完成,则方法或回调将被视为已完成。 值得强调的是,即使在不同方法、timer和回调中,基于回合的并发也一样起作用。
Dapr Actors 运行时通过在回合开始时获取每个 Actors 的锁定并在该回合结束时释放锁定来实施基于回合的并行。 因此,基于回合的并发性是按每个 actor 执行的,而不是跨 Actors 执行的。 Actor 方法和 timer/reminders 回调可以代表不同的 Actors 同时执行。
下面的示例演示了上述概念。 现在有一个实现了两个异步方法(例如,方法 1 和方法 2)、timer 和 reminders 的 actor。 下图显示了执行这些方法的时间线的示例,并代表属于此 Actors 类型的两个 Actors ( ActorId1 和 ActorId2) 的回调。
4.6 可观测性
1、集群的每一个Node配置DNS解析和地址映射
vim /etc/resolv.conf
###使用下面的dns或者其他的dns
nameserver ip
nameserver ip1### 添加地址映射 #########
vim /etc/hosts
ip2 raw.githubusercontent.com
2、k8s集群安装Dapr环境
### 初始化dapr环境 ##
dapr init -k
## 查看dapr初始化的状态######
dapr status -k
vim /etc/docker/daemon.json
"insecure-registries": [
"ip" #私服镜像仓库地址
]
systemctl daemon-reload && systemctl restart docker
### 登录镜像仓库
docker login ip
username: 输入账户
password: 输入密码
4、配置dapr相关组件
4.1、部署项目需要组件
状态管理 Redis
pubsub Redis/RabbitMQ(无缝切换组件)
链路追踪 Zipkin
## redis状态存储组件
kind: Deployment
apiVersion: apps/v1
metadata:
name: redis
labels:
service: redis
spec:
replicas: 1
selector:
matchLabels:
service: redis
template:
metadata:
labels:
app: eshop
service: redis
spec:
containers:
- name: redis
image: redis:alpine
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 6379
protocol: TCP
---
kind: Service
apiVersion: v1
metadata:
name: redis
labels:
app: eshop
service: redis
spec:
type: NodePort
ports:
- port: 6379
targetPort: 6379
nodePort: 30379
protocol: TCP
name: redis
selector:
service: redis
添加dapr状态组件
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: statestore
spec:
type: state.redis
version: v1
metadata:
- name: redisHost
value: redis:6379
- name: redisPassword
value: ""
- name: actorStateStore ### 在启动Actor必须配置
value: "true"
添加pubsub组件
## 部署RabbitMQ环境
kind: Deployment
apiVersion: apps/v1
metadata:
name: rabbitmq
labels:
service: redis
spec:
replicas: 1
selector:
matchLabels:
service: rabbitmq
template:
metadata:
labels:
app: eshop
service: rabbitmq
spec:
containers:
- name: rabbitmq
image: rabbitmq:3-management-alpine
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 5672
protocol: TCP
---
kind: Service
apiVersion: v1
metadata:
name: rabbitmq
labels:
service: rabbitmq
spec:
type: NodePort
ports:
- port: 5672
targetPort: 5672
nodePort: 32672
protocol: TCP
name: rabbitmq
- port: 15672
targetPort: 15672
nodePort: 32673
protocol: TCP
name: rabbitmq1
selector:
service: rabbitmq
添加dapr的rabbitmq发布订阅组件
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: pubsub
spec:
type: pubsub.rabbitmq
version: v1
metadata:
- name: host
value: "amqp://rabbitmq:5672"
添加链路追踪Zipkin组件
## 部署链接追踪应用
kind: Deployment
apiVersion: apps/v1
metadata:
name: zipkin
labels:
service: zipkin
spec:
replicas: 1
selector:
matchLabels:
service: zipkin
template:
metadata:
labels:
app: eshop
service: zipkin
spec:
containers:
- name: zipkin
image: openzipkin/zipkin-slim
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 9411
protocol: TCP
---
kind: Service
apiVersion: v1
metadata:
name: zipkin
labels:
app: eshop
spec:
type: NodePort
ports:
- port: 9411
targetPort: 9411
nodePort: 32411
protocol: TCP
name: zipkin
selector:
service: zipkin
添加dapr的链路追踪配置
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
name: dapr-config
spec:
tracing:
samplingRate: "1"
zipkin:
endpointAddress: "http://zipkin:9411/api/v2/spans"
4.2 部署微服务项目
kind: Deployment
apiVersion: apps/v1
metadata:
name: dapr-deploy-front
labels:
service: front
spec:
replicas: 1
selector:
matchLabels:
service: front
template:
metadata:
labels:
service: front
annotations:
dapr.io/enabled: "true"
dapr.io/app-id: "daprfrontend"
dapr.io/app-port: "80"
dapr.io/config: "dapr-config"
spec:
containers:
- name: daprfrontend
image: ip/dapr/frontend:v3
imagePullPolicy: Always
readinessProbe:
httpGet:
path: v1.0/healthz
port: 3500
initialDelaySeconds: 100
periodSeconds: 10timeoutSeconds : 30failureThreshold : 3
ports:
- name: http
containerPort: 80
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: daprfrontend
labels:
service: front
spec:
type: NodePort
ports:
- port: 80
targetPort: 80
nodePort: 30002
protocol: TCP
name: http
- port: 50001
targetPort: 50001
nodePort: 30041
protocol: TCP
name: dapr-grpc
selector:
service: front
附录
## 导出镜像文件
docker save > nginx.tar nginx:latest
## 导入镜像到本地镜像列表
docker load < nginx.tar
k8s安装redis的主从
1 helm安装
#根据操作系统去获取最新二进制安装包https://github.com/helm/helm/releases
wget https://get.helm.sh/helm-v3.3.1-linux-amd64.tar.gz
#由于helm包在国外,我通过ss拉到了腾讯云cos,国内可通过以下地址访问:https://download.osichina.net/tools/k8s/helm/helm-v3.3.1-linux-amd64.tar.gz
tar -zxvf helm-v3.3.1-linux-amd64.tar.gz
cp linux-amd64/helm /usr/local/bin/
helm verison # 验证是否成功
2 helm安装redis主从
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo update
helm search repo redis
helm install redis bitnami/redis
##########################问题###############################
kubectl describe pod redis-redis-b69965b4d-466d7 可以看到 “pod has unbound immediate PersistentVolumeClaims (repeated 2 times)”
##### 创建pv
cat > redis-pv.yml << EOF
kind: PersistentVolume
apiVersion: v1
metadata:
name: pv-volume
labels:
type: local
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/root/dapr-demo/redis/data"
EOF
kubectl apply -f redis-pv.yml
下载数据解压
helm fetch bitnami/redis --untar --untardir ./