Dapr微服务

**

一、Dapr是什么

**
官方解释:Dapr (Distributed Application Runtime)是一个可移植的、事件驱动的运行时

  • 可移植:指与软件从某一环境转移到另一环境下的难易程度。
  • 事件驱动:调用与被调用方解耦
    自己理解:Dapr为任何语言编写的应用(Any code or framwork),提供了与中间件解耦的模块

在这里插入图片描述

二、Dapr解决了什么问题 (SOA,MicroService)

目前微服务架构面临哪些问题

  • 微服务服务拓扑复杂,调用方式不同:HTTP,MQ,RPC。需要开发人员编写不同的Proxy实现。
  • 保存状态数据会使用不同组件,用Redis或者Mysql等不同存储。需要开发人员编写不同的存储类。
  • 保存密钥信息可能用Azure Keyvault或者K8S Secrets等不同密钥存储。需要开发人员集成不同SDK
  • 服务监测可能用不同中间件,需要开发人员侵入式编码。
    开发无法专注于业务,需要花很多时间了解很多的中间件。并且很多开发无法成为各个中间件的专家,无法正确搭建、使用中间件。

三、Sidecar架构(服务网格)【Serivce Mesh】

服务注册与发现
链路追踪
服务降级,熔断,限流,重试
服务网关
……
在这里插入图片描述

  • Sidecar为我们解决了服务调用、网络安全和分布式跟踪等功能
  • Dapr以 sidecar 架构的方式公开其API,可以是容器,也可以是进程,不需要应用代码包含任何 Dapr 运行时代码。 这使得 Dapr 与其他运行时的集成变得容易,在应用逻辑层面做了隔离处理,提高了可扩展性。

四、云平台和边缘计算的微服务构建块

在这里插入图片描述
在设计微服务应用时,需要考虑很多因素。 Dapr提供了一些常用功能的最佳实践,开发人员可以使用标准模式进行微服务应用的构建,并部署到任意环境中。 Dapr 通过提供分布式构建块来实现此目的。
每个构建块都是独立的,这意味着您可以采用其中一个、多个或全部来构建应用。 目前,可用的构建块如下:
在这里插入图片描述
4.1 服务的调用
4.1.1 介绍
通过服务调用,应用程序可以使用 gRPC 或 HTTP 这样的标准协议来发现并可靠地与其他应用程序通信。
在许多具有多个需要相互通信的服务的环境中,开发者经常会问自己以下问题:

  • 我如何发现和调用不同服务上的方法?
  • 我如何安全地调用其他服务?
  • 我如何处理重试和瞬态错误?
  • 我如何使用分布式跟踪来查看调用图来诊断生产中的问题?
    Dapr 通过提供服务调用 API 来应对这些问题,这种调用 API 作为反向代理与内置的服务发现相结合, 同时利用内置分布式跟踪、计量、错误处理、加密等功能。
    4.1.2 调用逻辑
    在这里插入图片描述
  1. 服务 A 对服务 B 发起HTTP/gRPC的调用。
  2. Dapr使用在给定主机平台上运行的名称解析组件发现服务B的位置。
  3. Dapr 将消息转发至服务 B的 Dapr 边车
    注: Dapr 边车之间的所有调用考虑到性能都优先使用 gRPC。 仅服务与 Dapr 边车之间的调用可以是 HTTP 或 gRPC
  4. 服务 B的 Dapr 边车将请求转发至服务 B 上的特定端点 (或方法) 。 服务 B 随后运行其业务逻辑代码。
  5. 服务 B 发送响应给服务 A。 响应将转至服务 B 的边车。
  6. Dapr 将消息转发至服务 A 的 Dapr 边车。
  7. 服务 A 接收响应。

4.1.3 特征
提供不同调用方式

  • Http
  • GRPC
    可插拔服务发现组件
  • mDNS
  • K8S DNS
  • Consul
    服务重试
    调用安全性mTLS
    https://docs.dapr.io/zh-hans/developing-applications/building-blocks/service-invocation/service-invocation-overview/

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允许开发人员在对于状态的操作请求中附加额外的元数据,这些元数据用以描述期望如何处理该请求。 你可以附加以下:

  • 并发要求
  • 一致性要求
    默认情况下,您的应用程序应该假设数据存储是最终一致的,并使用last-write-wins并发模式。
    Not all stores are created equal. 为了保证应用程序的可移植性,你可以了解下存储引擎的功能,使你的代码适应不同的存储引擎。
    并发(Concurrency)
    Dapr支持使用ETags的乐观并发控制(OCC)。 当一个发送请求操作状态时,Dapr会给返回的状态附加一个ETag属性。 当用户代码试图更新或删除一个状态时,它应该通过更新的请求体或删除的If-Match头附加ETag。 只有当提供的ETag与状态存储中的ETag匹配时,写操作才能成功。
    Dapr之所以选择OCC,是因为在不少应用中,数据更新冲突都是很少的,因为客户端是按业务上下文自然分割的,可以对不同的数据进行操作。 然而,如果你的应用选择使用ETags,请求可能会因为不匹配的ETags而被拒绝。 建议你在使用ETags时,使用重试策略来补偿这种冲突。
    如果您的应用程序在书面请求中省略了ETags,Dapr会在处理请求时跳过ETags校验。 这与ETags的last-write-wins模式相比,基本上可以实现first-write-wins模式。
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 组件。 这种方法消除了您服务的依赖性,从而使您的服务可以更便携,更灵活地适应更改。

在这里插入图片描述
4.4 绑定

  • 除去连接到消息传递系统 ( 如队列和消息总线 ) 并进行轮询的复杂性
  • 聚焦于业务逻辑,而不是如何与系统交互的实现细节
  • 使代码不受 SDK 或库的跟踪
  • 处理重试和故障恢复
  • 构建具有特定于环境的绑定的可移植应用程序,不需要进行代码更改
    4.5 Actors
    4.5.1 介绍
    actor 模式 阐述了 Actors 为最低级别的“计算单元”。 换句话说,您将代码写入独立单元 ( 称为actor) ,该单元接收消息并一次处理消息,而不进行任何类型的并行或线程处理。
    当代码处理一条消息时,它可以向其他参与者发送一条或多条消息,或者创建新的 Actors。 底层 运行时 将管理每个 actor 的运行方式,时机和位置,并在 Actors 之间传递消息。
    大量 Actors 可以同时执行,而 Actors 可以相互独立执行。
    Dapr 包含专门实现 virtual actors 模式 的运行时。 通过 Dapr 的实现,您可以根据 Actors 模型编写 Dapr Actor,而 Dapr 利用底层平台提供的可扩展性和可靠性保证。
    4.5.2 何时使用Actors
    与任何其他技术决策一样,您应该根据您尝试解决的问题来决定是否使用 Actors。
    Actor 设计模式可以很好适应一些分布式系统问题和场景,但您首先应该考虑的是模式的约束。 一般来说,在下列情况下,考虑 actor 模式来模拟你的问题或场景:
  • 您的问题空间涉及大量(数千或更多) 的独立和孤立的小单位和逻辑。
  • 您想要处理单线程对象,这些对象不需要外部组件的大量交互,例如在一组 Actors 之间查询状态。
  • 您的 actor 实例不会通过发出I/O操作来阻塞调用方。
    4.5.3 Dapr 中的 Actors
    每个 actor 都定义为 actor 类型的实例,与对象是类的实例的方式相同。 例如,可能存在实现计算器功能的 actor 类型,并且该类型的许多 Actors 分布在集群的各个节点上。 每个这样的 actor 都是由一个 actor ID 确定的。
    在这里插入图片描述
    4.5.3.1 Actor 生命周期
    Dapr Actors 是虚拟的,意思是他们的生命周期与他们的 in - memory 表现不相关。 因此,它们不需要显式创建或销毁。 Dapr Actors 运行时在第一次接收到该 actor ID 的请求时自动激活 actor。 如果 actor 在一段时间内未被使用,那么 Dapr Actors 运行时将回收内存对象。 如果以后需要重新启动,它还将保持对 actor 的一切原有数据。
    调用 actor 方法和 reminders 将重置空闲时间,例如,reminders 触发将使 actor 保持活动状态。 不论 actor 是否处于活动状态或不活动状态 Actor reminders 都会触发,对不活动 actor ,那么会首先激活 actor。 Actor timers 不会重置空闲时间,因此 timer 触发不会使参与者保持活动状态。 Timer 仅在 actor 活跃时被触发。
    空闲超时和扫描时间间隔 Dapr 运行时用于查看是否可以对 actor 进行垃圾收集。 当 Dapr 运行时调用 actor 服务以获取受支持的 actor 类型时,可以传递此信息。
    Virtual actors 生命周期抽象会将一些警告作为 virtual actors 模型的结果,而事实上, Dapr Actors 实施有时会偏离此模型。
    在第一次将消息发送到其 actor 标识时,将自动激活 actor ( 导致构造 actor 对象) 。 在一段时间后,actor 对象将被垃圾回收。 以后,再次使用 actor ID 访问,将构造新的 actor。 Actor 的状态比对象的生命周期更久,因为状态存储在 Dapr 运行时的配置状态提供程序中(也就是说Actor即使不在活跃状态,仍然可以读取它的状态)。
    4.5.3.2 分发和故障转移
    为了提供可扩展性和可靠性,Actors 实例分布在整个集群中, Dapr 会根据需要自动将对象从失败的节点迁移到健康的节点。
    Actors 分布在 actor 服务的实例中,并且这些实例分布在集群中的节点之间。 每个服务实例都包含给定 Actors 类型的一组 Actors。
    4.5.4 Actor 安置服务 (Actor placement service)
    Dapr actor 运行时为您管理分发方案和键范围设置。 这是由 actor Placement 服务完成的。 创建服务的新实例时,相应的 Dapr 运行时将注册它可以创建的 actor 类型, Placement 服务将计算给定 actor 类型的所有实例之间的分区。 每个 actor 类型的分区信息表将更新并存储在环境中运行的每个 Dapr 实例中,并且可以随着新 actor 服务实例创建和销毁动态更改。 如下图所示。

在这里插入图片描述
当客户端调用具有特定标识的 actor ( 例如,actor Id 123) 时,客户端的 Dapr 实例将散列 actor 类型和 Id,并使用该信息来调用相应的 Dapr 实例,该实例可以为该特定 actor Id提供请求。 因此,始终对任何给定 actor Id 始终会落在同一分区 (或服务实例) 。 如下图所示。
在这里插入图片描述
这简化了一些选择,但也带有一些考虑:

  • 默认情况下,Actors 被随机放入分区中,从而形成均匀的分布。
  • 由于 Actors 是随机放置的,因此可知,执行操作始终需要网络通信,包括方法调用数据的序列化和去序列化,产生延迟和开销。
    注: Dapr actor Placement 服务仅用于 actor 安置,因此,如果您的服务未使用 Dapr Actors,那么不需要。 The Placement service can run in all hosting environments, including self-hosted and Kubernetes.
    4.5.5 Actor 通信
    您可以通过 HTTP/gRPC 来与 Dapr 交互以调用 actor 方法.
    Copy
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 可观测性
在这里插入图片描述

  • W3C标准分布式跟踪
  • 健康监测
  • 指标收集
  • 日志收集
    4.7 密钥管理
    应用程序通常会通过使用专用的密钥存储来秘密存储敏感信息,如连接字符串、密钥和用于与数据库、服务和外部系统进行验证的令牌。
    通常这需要建立一个密钥存储,如Azure Key Vault、Hashicorp 保险库和其他仓库,并在那里存储应用程序级别的密钥。 要访问这些密钥存储,应用程序需要导入密钥存储SDK,并使用它访问这些密钥。 这可能需要相当数量的模板代码,这些代码与应用的实际业务领域无关,因此在多云场景中,可能会使用不同厂商特定的密钥存储,这就成为一个更大的挑战。
    让开发人员在任何地方更容易消耗应用程序密钥, Dapr 有一个专用的密钥构建块 API ,允许开发人员从一个密钥存储获得密钥。
    使用 Dapr 的密钥存储构建块通常涉及以下内容:
  1. 设置一个特定的密钥存储解决方案的组件。
  2. 在应用程序代码中使用 Dapr 密钥 API 获取密钥。
  3. 可选,在Dapr组件文件中引用密钥。
    在这里插入图片描述

五、Dapr部署到Kubernetes

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

在这里插入图片描述
3、配置Harbor镜像仓库

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 ./

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【通过Cpython3.9源码看看列表到底是咋回事】

列表结构 typedef struct {PyObject_VAR_HEAD/* Vector of pointers to list elements. list[0] is ob_item[0], etc. */PyObject **ob_item;/* ob_item contains space for allocated elements. The number* currently in use is ob_size.* Invariants:* 0 < ob_siz…

Matlab论文插图绘制模板第85期—模值赋色的箭头图

在之前的文章中&#xff0c;分享了Matlab箭头图的绘制模板&#xff1a; 进一步&#xff0c;如果我们想对每一个箭头赋上颜色&#xff0c;以更加直观地表示其模值的大小&#xff0c;该怎么操作呢&#xff1f; 那么&#xff0c;来看一下模值赋色的箭头图的绘制模板。 先来看一下…

老胡的周刊(第086期)

老胡的信息周刊[1]&#xff0c;记录这周我看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。&#x1f3af; 项目MochiDiffusion[2]在 MacOS 上运行原生的 Stab…

游戏解密之常见网络游戏同步方式分析

一、为什么需要有同步呢&#xff1f; 同步机制是用来维护游戏的一致性&#xff0c;通俗的说就是虚拟世界中的事实&#xff1b;比如在CF中&#xff0c;大家的PING都很高&#xff0c;A和B两个玩家同时发现了对方&#xff0c;并向对方开火&#xff0c;如果没有很好的同步机制&…

【学习笔记】滑动窗口

acwing.滑动窗口https://www.acwing.com/problem/content/156/ 给定一个大小为 n≤106≤106 的数组。 有一个大小为 k 的滑动窗口&#xff0c;它从数组的最左边移动到最右边。 你只能在窗口中看到 k 个数字。 每次滑动窗口向右移动一个位置。 以下是一个例子&#xff1a; …

【博学谷学习记录】超强总结,用心分享 | 架构师 MySql扩容学习总结

文章目录1. 停机方案2.停写方案3.日志方案4.双写方案&#xff08;中小型数据&#xff09;5.平滑2N方案&#xff08;大数据量&#xff09;1. 停机方案 发布公告 为了进行数据的重新拆分&#xff0c;在停止服务之前&#xff0c;我们需要提前通知用户&#xff0c;比如&#xff1a…

他98年的,我真的玩不过他...

现在的小年轻真的卷得过分了。前段时间我们公司来了个98年的&#xff0c;工作没两年&#xff0c;跳槽到我们公司起薪18K&#xff0c;都快接近我了。后来才知道人家是个卷王&#xff0c;从早干到晚就差搬张床到工位睡觉了。 最近和他聊了一次天&#xff0c;原来这位小老弟家里条…

MySQL 分布式数据库实现:无需修改代码,轻松实现分布式能力

这个项目做什么 ShardingSphere-Proxy&#xff0c;可以让用户像使用原生数据库一样使用 Apache ShardingSphere。 了解一项技术的开始&#xff0c;一般从官网开始。先来看一看官网对 ShardingSphere-Proxy 的定义是什么样的&#xff1a; 定位为透明化的数据库代理端&#xff…

springboot学习2

一、spring boot自动装配原理 pom.xml spring-boot-dependencies 核心依赖在父工程中 在写或者引入一些spring boot依赖的时候&#xff0c;不需要指定版本&#xff0c;因为有这些版本仓库启动器 <dependency><groupId>org.springframework.boot</groupId>&…

会画画的海龟,Python Turtle库详解(27)

小朋友们好&#xff0c;大朋友们好&#xff01; 我是猫妹&#xff0c;一名爱上Python编程的小学生。 欢迎和猫妹一起&#xff0c;趣味学Python。 今日主题 介绍下Python的turtle库&#xff0c;这是一个可以画画的库&#xff0c;非常适合小孩子在屏幕上画画。 先学习基础知…

第08章_面向对象编程(高级)

第08章_面向对象编程(高级) 讲师&#xff1a;尚硅谷-宋红康&#xff08;江湖人称&#xff1a;康师傅&#xff09; 官网&#xff1a;http://www.atguigu.com 本章专题与脉络 1. 关键字&#xff1a;static 回顾类中的实例变量&#xff08;即非static的成员变量&#xff09; c…

虚拟化技术:实现资源高效利用和灵活管理的利器

虚拟化技术是一种通过软件或硬件手段&#xff0c;将物理资源抽象化&#xff0c;从而创建虚拟资源的技术。这种技术可以应用于计算、存储、网络等领域&#xff0c;通过将物理资源划分为多个虚拟资源&#xff0c;使得多个应用程序或用户可以共享同一组物理资源&#xff0c;从而提…

Linux 进程管理之四大名捕

一、四大名捕 四大名捕&#xff0c;最初出现于温瑞安创作的武侠小说&#xff0c;是朝廷中正义力量诸葛小花的四大徒弟&#xff0c;四人各怀绝技&#xff0c;分别是轻功暗器高手 “无情”、内功卓越的高手“铁手”、腿功惊人的“追命” 和剑法一流的“冷血”。 本文四大名捕由…

关于电商商品数据API接口列表,你想知道的(详情页、Sku信息、商品描述、评论问答列表)

目录 一、商品数据API接口列表 二、商品详情数据API调用代码item_get 三、获取sku详细信息item_sku 四、获得淘宝商品评论item_review 五、数据说明文档 进入 一、商品数据API接口列表 二、商品详情数据API调用代码item_get <?php// 请求示例 url 默认请求参数已经URL…

集合-LinkedList

LinkedList LinkedList的概述 LinkedList的底层使用双向链表实现。 链表是一种线性数据结构&#xff0c;其中每个元素都是一个单独的对象&#xff0c;包含一个指向列表中下一个节点的引用。 它可以用于实现各种抽象数据类型&#xff0c;例如列表、堆栈、队列等。 LinkedLis…

Carla仿真二:Carla多视图切换代码详解

文章目录前言一、Carla多视图切换效果二、Camera安装坐标系1、Carla.Location2、Carla.Rotation三、接口及代码详解1、接口介绍2、生成上帝视图代码3、生成Camera视图代码四、完整代码前言 1、Carla提供了大量的Python API接口&#xff0c;用户可以通过查找文档实现各类功能&a…

无限制翻译软件-中英互译字数无限

翻译软件是我们工作及学习中必不可少的工具&#xff0c;然而许多翻译软件在使用时常常会出现字数限制的问题,这使得用户在处理长文本和大量文本时变得十分麻烦。如果你也遇到了类似的问题&#xff0c;那么哪个翻译软件不限制字数将为您带来全新的翻译体验。 以下是我们的哪个翻…

Vite打包后直接使用浏览器打开,显示空白问题

vite打包后&#xff0c;直接用浏览器打开显示空白 1.需求&#xff1a; 安卓webview等浏览器直接打开文件显示 2.原因 &#xff08;1&#xff09;资源路径错误&#xff1a; vite.config.js 配置 base: “./” &#xff08;在webpack中则配置publicPath: "./"即可…

ATTCK v12版本战术实战研究——提权(一)

一、概述 前几期文章中&#xff0c;我们中介绍ATT&CK 14项战术中提权战术&#xff08;一&#xff09;&#xff0c;包括提权前6项子技术。那么从前文中介绍的相关提权技术来开展测试&#xff0c;进行更深一步的分析。本文主要内容是介绍攻击者在运用提权技术时&#xff0c;…

算法 贪心2 || 122.买卖股票的最佳时机II 55. 跳跃游戏 45.跳跃游戏II

122.买卖股票的最佳时机II 如果想到其实最终利润是可以分解的&#xff0c;那么本题就很容易了&#xff01; 如何分解呢&#xff1f; 假如第0天买入&#xff0c;第3天卖出&#xff0c;那么利润为&#xff1a;prices[3] - prices[0]。 相当于(prices[3] - prices[2]) (prices[2…