Dawn's Blogs

分享技术 记录成长

0%

多集群部署方案

Kuma 支持多区域部署,甚至是 Kubernetes 集群和 Universal 集群的混合部署。

Kuma 服务网格多区域部署,无区域出口

运行机制

在 Kuma 中将服务标记以 kuma.io/service 标签标记,这意味着运行在任何地方的数据平面代理可以通过 kuma.io/service 标签值找到该服务。不同区域上的同一服务用相同的 kuma.io/service 标记,可以在特定区域发生故障时自动进行服务故障转移

如果一个新的后端服务 serviceA 部署在区域 zone-b,下面看这两个问题。

  1. 这个新的后端服务如何被通告到 zone-a 区域(区域间的同步)。
  2. 一个来自于 zone-a 区域的请求如何被路由到 zone-b 区域(区域间的请求路由)。

区域间的信息同步

当 zone-b 区域中加入了一个新的服务 serviceA 后,区域间的信息同步如下:

  • zone-b 的控制面将该服务加入到 zone-b Ingress 资源的 availableServices(可用服务列表)中,Ingress 持有可用服务列表,以便可以路由区域外的请求。
  • zone-b 的控制平面也会将该区域的 Ingress 资源信息(Ingress 的地址等),同步到 Global 全局控制平面
  • 全局控制平面将通过 Kuma 发现服务(KDS,基于 xDS 的协议)将区域入口 Ingress 资源和所有策略传播到所有其他区域

区域间的请求路由

当 zone-a 中有请求想请求 serviceA 服务时:

  • 首先会进行本地服务和远程服务之间的负载均衡,决定发往本区域服务还是远程区域服务。
  • 如果存在区域 Egress,流量会先通过本地区域 zone-a 出口进行路由,然后再发送到远程区域 zone-b 入口
  • 远程区域 zone-b 入口收到请求后,路由到本地服务 ServiceA。

对于负载平衡,是根据其后面运行的实例数量进行加权。因此,具有 2 个实例的区域接收的流量是具有 1 个实例的区域的两倍。可以配置位置感知的负载均衡,来支持本地服务实例。

组件

多区域部署包括:

  • 全局控制平面(Global kuma-cp):
    • 仅接受来自区域控制平面的连接
    • 接受对将应用于数据平面代理的策略的创建和更改
    • 将策略发送到区域控制平面
    • 将区域入口向下发送到区域控制平面
    • 保留所有区域中运行的所有数据平面代理的清单(这样做只是为了可观察性,但对于操作不是必需的)。
    • 拒绝来自数据平面代理的连接。
  • 区域控制平面(Zone kuma-cp):
    • 接受来自该区域内启动的数据平面代理的连接
    • 从全局控制平面接收策略更新
    • 将数据平面代理和区域入口的更改发送到全局控制平面
    • 使用 XDS 计算配置并将其发送到本地数据平面代理
    • 更新区域入口中区域中存在的服务列表。
    • 拒绝非来自全球的政策变化。
  • 数据平面代理(Envoy):
    • 连接到本地区域控制平面。
    • 使用 XDS 从本地区域控制平面接收配置
    • 连接到其他本地数据平面代理。
    • 连接到区域入口以发送跨区域流量。
    • 从本地数据平面代理和本地区域入口接收流量。
  • 区域入口(Ingress):
    • 从本地区域控制平面接收 XDS 配置。
    • 从其他区域数据平面代理到本地数据平面代理的代理流量。
  • (可选)区域出口(Egress):
    • 从本地区域控制平面接收 XDS 配置。
    • 来自本地数据平面代理的代理流量:
      • 来自其他区域的区域入口代理;
      • 从本地区域到外部服务。

跨区域服务发现和连接

KDS

在多区域部署中,Kuma 提供了几个重要功能:

  • 两种控制平面,global 和 zone 控制面。
  • 一种新的 DNS,用于跨集群通信。
  • 一种新的 Ingress 数据平面代理,可以在 Kuma service mesh 实现区域之间的连接。

在分布式部署中,global 控制平面将负责接受 Kuma 资源,通过原生 Kubernetes CRD 或基于 VM 的部署中的 YAML 来确定服务网格的行为。

介绍

Global 将负责将这些资源传播到 zone 控制平面。zone 控制平面和 global 控制平面通过 KDS(Kuma Discovery Service)以 gRPC(H2)的方式进行资源的同步。Zone 控制面还会接收来自于数据面的请求,zone 控制面和其下的所有控制平面代理属于同一区域。

Zone 控制平面还嵌入一个 DNS 服务发现,可用于跨不同区域的服务。

分层的好处

global 和 zone 架构有几个好处:

  • 可以通过拓展 zone 控制平面来独立拓展每个区域,并且在某个区域出现问题的时候实现 HA 故障转移
  • 没有单点故障。即使 global 控制平面发生故障,仍然可以在 zone 控制平面上创建和销毁数据平面代理,并且每个服务的最新地址仍然可以传播到 sidecar 中。
  • global 控制平面自动传播每个区域的状态,同时确保“远程”控制平面了解每个区域的Kuma Ingress,以实现跨区域连接

Kuma 提供的部署模式在 service mesh 领域非常独特,有两种部署模式:

  • 独立式:Kuma 的默认部署模型具有一个控制平面(可以水平扩展)和许多直接与其连接的数据平面。
  • 多区域:Kuma 的高级部署模型支持多个 Kubernetes 或基于 VM 的区域,或在 Kubernetes 和 VM 上运行的混合服务网格。

独立部署

这是 Kuma 最简单的部署模式,也是默认的部署模式。

  • 控制平面:有一种可以水平扩展的控制平面部署。
  • 数据平面代理:数据平面代理连接到控制平面,无论部署在何处。
  • 服务连接性:每个数据平面代理都必须能够连接到每个其他数据平面代理,无论它们部署在何处。

img

独立部署模式下,有一定的局限性:

  • 要求所有的数据平面代理与其他所有的数据平面代理都能进行通信
  • 独立部署只能连接到一个集群
  • 无法混合 Universal 和 Kubernetes 集群工作负载。

组件

独立部署包括:

  • 控制平面(kuma-cp):
    • 接受来自数据平面代理的连接。
    • 接受对将应用于数据平面代理的策略的创建和更改。
    • 保存所有正在运行的数据平面代理的清单。
    • 使用 XDS 将配置发送到数据平面代理。
  • 数据平面代理(envoy):
    • 连接到区域控制平面。
    • 使用 XDS 从控制平面接收配置。
    • 连接到其他数据平面代理。

失效模式

控制平面离线:

  • 新的数据平面代理将无法加入网格。这包括通过自动部署机制(例如滚动更新过程)新创建的新实例(Pod/VM),这意味着控制平面连接故障可能会阻止应用程序的更新和创建新实例的事件。
  • 在启用 mTLS 的网格上,数据平面代理可能无法在到期(默认为 24 小时)之前刷新其客户端证书,从而导致来自/流向该数据平面的流量失败。
  • 数据平面代理配置将不会更新
  • 数据平面代理之间的通信仍然有效

多区域部署

Kuma 支持多区域部署,甚至是 Kubernetes 集群和 Universal 集群的混合部署。

Kuma 服务网格多区域部署,无区域出口

运行机制

在 Kuma 中将服务标记以 kuma.io/service 标签标记,这意味着运行在任何地方的数据平面代理可以通过 kuma.io/service 标签值找到该服务。不同区域上的同一服务用相同的 kuma.io/service 标记,可以在特定区域发生故障时自动进行服务故障转移

如果一个新的后端服务 serviceA 部署在区域 zone-b,下面看这两个问题。

  1. 这个新的后端服务如何被通告到 zone-a 区域(区域间的同步)。
  2. 一个来自于 zone-a 区域的请求如何被路由到 zone-b 区域(区域间的请求路由)。

区域间的信息同步

当 zone-b 区域中加入了一个新的服务 serviceA 后,区域间的信息同步如下:

  • zone-b 的控制面将该服务加入到 zone-b Ingress 资源的 availableServices(可用服务列表)中,Ingress 持有可用服务列表,以便可以路由区域外的请求。
  • zone-b 的控制平面也会将该区域的 Ingress 资源信息(Ingress 的地址等),同步到 Global 全局控制平面
  • 全局控制平面将通过 Kuma 发现服务(KDS,基于 xDS 的协议)将区域入口 Ingress 资源和所有策略传播到所有其他区域

区域间的请求路由

当 zone-a 中有请求想请求 serviceA 服务时:

  • 首先会进行本地服务和远程服务之间的负载均衡,决定发往本区域服务还是远程区域服务。
  • 如果存在区域 Egress,流量会先通过本地区域 zone-a 出口进行路由,然后再发送到远程区域 zone-b 入口
  • 远程区域 zone-b 入口收到请求后,路由到本地服务 ServiceA。

对于负载平衡,是根据其后面运行的实例数量进行加权。因此,具有 2 个实例的区域接收的流量是具有 1 个实例的区域的两倍。可以配置位置感知的负载均衡,来支持本地服务实例。

组件

多区域部署包括:

  • 全局控制平面(Global kuma-cp):
    • 仅接受来自区域控制平面的连接
    • 接受对将应用于数据平面代理的策略的创建和更改
    • 将策略发送到区域控制平面
    • 将区域入口向下发送到区域控制平面
    • 保留所有区域中运行的所有数据平面代理的清单(这样做只是为了可观察性,但对于操作不是必需的)。
    • 拒绝来自数据平面代理的连接。
  • 区域控制平面(Zone kuma-cp):
    • 接受来自该区域内启动的数据平面代理的连接
    • 从全局控制平面接收策略更新
    • 将数据平面代理和区域入口的更改发送到全局控制平面
    • 使用 XDS 计算配置并将其发送到本地数据平面代理
    • 更新区域入口中区域中存在的服务列表。
    • 拒绝非来自全球的政策变化。
  • 数据平面代理(Envoy):
    • 连接到本地区域控制平面。
    • 使用 XDS 从本地区域控制平面接收配置
    • 连接到其他本地数据平面代理。
    • 连接到区域入口以发送跨区域流量。
    • 从本地数据平面代理和本地区域入口接收流量。
  • 区域入口(Ingress):
    • 从本地区域控制平面接收 XDS 配置。
    • 从其他区域数据平面代理到本地数据平面代理的代理流量。
  • (可选)区域出口(Egress):
    • 从本地区域控制平面接收 XDS 配置。
    • 来自本地数据平面代理的代理流量:
      • 来自其他区域的区域入口代理;
      • 从本地区域到外部服务。

失效模式

全局控制平面离线

  • 政策更新将不可能
  • 区域之间服务列表的更改不会传播:
    • 在其他区域中将无法发现新服务。
    • 从区域中删除的服务在其他区域中仍将显示为可用。
  • 无法禁用或删除区域

本地和跨区域应用程序流量均不会受到此故障情况的影响;数据平面代理更改将在其区域内传播。

区域控制平面离线

  • 新的数据平面代理将无法加入网格。这包括通过自动部署机制(例如滚动更新过程)新创建的新实例(Pod/VM),这意味着控制平面连接故障可能会阻止应用程序的更新和创建新实例的事件。
  • 在启用 mTLS 的网格上,数据平面代理可能无法在到期(默认为 24 小时)之前刷新其客户端证书,从而导致来自/流向该数据平面的流量失败。
  • 数据平面代理配置将不会更新。
  • 数据平面代理之间的通信仍然有效。
  • 跨区域通信仍然有效。
  • 其他区域不受影响。

这种故障案例,与独立部署的控制平面离线故障一致

全局和区域控制平面之间的通信失效

控制平面之间的配置错误或网络连接问题可能会发生这种情况:

  • 区域内的操作是正常的(数据平面代理可以加入、离开,所有配置都将正确更新和发送)。

  • 策略更改不会传播到区域控制平面

  • 区域 Ingress,区域 Egress 和数据平面的变更不会传播到全局控制平面:

    • 数据平面代理的全局清单视图将过时(这只会影响可观察性)。
    • 其他区域不会看到该区域内注册的新服务。
    • 其他区域不会看到该区域不再运行某服务。
    • 其他区域不会看到本地区域中运行的每个服务的实例数量发生变化。
  • 全局控制平面不会将其他区域入口的更改发送到该区域:

    • 本地数据平面代理不会看到在其他区域注册的新服务。
    • 本地数据平面代理将看不到其他区域不再运行某服务。
    • 本地数据平面代理不会看到在其他区域中运行的每个服务的实例数量的变化。

本地和跨区域应用程序流量均不会受到此故障情况的影响。

两个区域之间的通信失效

如果存在区域之间的网络连接问题,可能是以下原因:

  • 在控制平面和来自其他区域的区域入口之间。
  • 在控制平面和区域出口之间(如果存在)。
  • 在区域出口(如果存在)和其他区域的区域入口之间。
  • 区域的所有区域出口实例(如果存在)均已关闭。
  • 区域的所有区域入口实例均已关闭。

当它发生时:

  • 每个区域的通信和操作不受影响
  • 每个区域之间的通信将失败

通过配置正确的弹性设置(重试、探针、局部感知负载均衡、断路器),可以快速切断故障区域并将流量重新路由到另一个区域。

概述

介绍

Kuma 是一个与平台无关的开源控制平面,用于 service mesh 和微服务的管理,支持 Kubernetes,VM 和 裸机环境。Kuma 有以下特性:

  • 兼容通用环境和 Kubernetes 环境:与平台无关,可以在任何地方运行和操作。
  • 独立和多区域:可以独立部署,也支持多区域、多集群。
  • 多服务网格:可以通过一个控制平面管理多个单独的服务网格,降低整个组织的运维成本。
  • 基于属性的策略:允许通过 tag 细粒度的选择 source 和 destination 策略。
  • 基于 Envoy:采用 Envoy 作为数据平面。
  • 水平扩展

Kuma 多集群部署示例图如下:

Kuma 服务网格多区域部署

工作原理

Sidecar

在编写网络应用程序时,会遇到可观测性、流量管理、安全性等共性问题。可以当然可以采用 sdk 的形式去将这些问题集成在框架中,但这是和语言相关的,必须为每一种编程语言提供这样的 sdk,并且需要考虑不同语言之间的兼容性问题。

一个想法是采用 sidecar 代理:将所有网络连接中可观测性、流量管理等问题,委托给进程外的 sidecar 完成,sidecar 接管所有传入和穿出的请求和响应。开发人员可以专注于应用程序本身,而不是处理复杂的网络问题上去。

由于一个系统具有多个服务,每一个服务有许多实例,这要求具有相同数量的代理。因此,sidecar 代理模型需要一个控制平面,允许动态配置代理的行为,而无需手动配置它们。代理与控制平面的连接以接收新配置,控制平面也为代理提供最新的配置。

服务网格包括数据平面和控制平面,通常服务网格出现在 Kubernetes 环境中,但是任何环境(VM 和裸机)上都可以构建服务网格)。

运行模式

kuma-cp 是 Kuma 控制面的可执行文件,支持通用环境和 Kubernetes 环境

  • 在 Kubernetes 上运行:不需要外部依赖,利用 K8s API 服务器存储配置
  • 在通用环境上运行:Kuma 需要 PostgreSQL 数据库作为依赖项,用于存储配置。

架构

Kuma 网络由数据平面和控制平面两个部分组成:

  • 数据平面:由一个个应用服务+Sidecar 代理组成,在数据平面中代理接管网络流量,Kuma 采用 Envoy 作为数据平面代理
  • 控制平面:用于配置数据平面,独立于数据平面运行。用户可以在控制平面配置策略,控制平面生成数据平面配置并分发到数据平面。Kuma 实现了Envoy xDS API ,以便数据平面代理可以从控制平面检索其配置。

img

Kuma 按照运行环境的不同,分为 Kubernetes 和通用(universal)两种运行模式。

Kubernetes 模式

当在 Kubernetes 模式下运行时,Kuma 将其所有状态和配置存储在底层 Kubernetes API 服务器上

img

将 Kubernetes 中的服务加入服务网格进行管理的唯一步骤就是开启 Sidecar 注入kuma.io/sidecar-injection: enabled 标签用于将 sidecar 注入到 pod 中。

Services 和 Pods

  • 对于一个 Kubernetes Service 和关联的 Pod,Kuma 控制面会自动的生成一个注解 kuma.io/service: <name>_<namespace>_svc_<port>,其中 name 和 namespace 还有 port 均来自 Service 信息。

  • 某些情况下 Pods 不属于任何的 Service,仅仅是单纯的一个 Pod。在这种情况下,Kuma 会自动生成的注解为 kuma.io/service: <name>_<namespace>_svc ,其中 name 和 namespace 来自于 Pod 资源。

Universal 模式

在通用模式下运行时,Kuma 需要 PostgreSQL 数据库来存储其状态

img

以下是 CA 安全性的概述,分为两个部分:

  • 控制面:实现了一个 CA 负责为网格中的各个服务签发证书,并将证书颁发给各个服务,具体的做法有两个:

    • 通过(webhook)动态准入控制器的方式,将 CA 的证书挂载到 Pod 里面去,同时添加了环境变量,只需要读取环境变量就可以获取路径了。
    • Dubbo 应用通过与 CA 建立双向 TLS 连接(CA 证书已经被挂载到了 Pod 中,所以可以验证 CA 证书),发送 CSR 请求申请这个 dubbo 应用的证书,dubbo-cp 会验证客户端的 CSR 请求并签发证书返回给客户端。
  • 数据面:在网格中服务相互之前发起通信的时候,dubbo sdk 会拦截服务请求,采用证书进行双向 TLS 认证并建立一个 TLS 连接,使用该 TLS 连接来在网格中传输数据。

1703656322

在 dubbo-cp 中,要实现一个 CA 要做两方面的事情:

  1. 维护 CA:维护 CA 的证书状态,存储 CA 证书。
  2. 签发证书:接受 CSR 请求,为 Dubbo 应用签发证书。
阅读全文 »

类似于 istio 中的 xDS,在 dubbo-kubernetes 中 dds 组件做了一些对于 dubbo 规则的监听与分发。它的作用是接受各种 dubbo 规则(留了管控、认证、授权),将规则下发至各个 dubbo 应用,完成具有 dubbo 特色的服务治理。即作为控制面,将规则下发到数据面进行应用。

image-20231225215623017

对于 dds 而言,当一个客户端连接到 dubbo-cp dds,dubbo 规则的推送主要来自两个方面:

  1. Informer 机制监听到 CRD 资源发生变化,主动推送消息给客户端。
  2. 客户端发生 Request 请求,dds 服务器进行响应

dds 接口定义如下,因为推送的机制,所以定义为双向 streaming:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
message ObserveRequest {
string nonce = 1;
string type = 2;
}

message ObserveResponse {
string nonce = 1;
string type = 2;
int64 revision = 3;
repeated google.protobuf.Any data = 4;
}

service RuleService {
rpc Observe(stream ObserveRequest)
returns (stream ObserveResponse) {
}
}
阅读全文 »

本项目地址:LMQ

Lookup

LMQ Lookup 的功能就是存储 LMQ 分布式拓扑结构,为客户端提供查询服务。

拓扑结构

Lookup 维护了 lmqd,topic 和 channel 之间的拓扑结构,三者的对应关系如下。其中,lmqd 和 topic 为多对多的关系,topic 和 channel 为一对多的关系。

1
lmqd(producer) <--- M:N ---> topic <--- 1:N ---> channel

存储结构

根据 lookup 维护的拓扑结构,look 主要维护了这样一个注册字典:

  • 字典的键值分为两种类型,channel 和 topic。
  • 字典的值是对应的所有的生产者(Lmqd)。
1
2
3
4
type RegistrationDB struct {
sync.RWMutex
registrationMap map[iface.IRegistration]iface.ProducerMap
}

所以,存储结构如下:

1
2
3
4
5
6
7
{topic, topicName1, ""} ---> [{id1: producer1}, {id2: producer2}, ...]
{topic, topicName2, ""} ---> [{id3: producer3}, {id4: producer4}, ...]
...

{channel, topicName1, channelName1} ---> [{id1: producer1}, {id2: producer2}, ...]
{channel, topicName2, channelName2} ---> [{id3: producer3}, {id4: producer4}, ...]
...
阅读全文 »

本项目地址:LMQ

消息格式

LMQ 中的消息格式包括一个全局唯一的 ID(用分布式雪花 ID 生成的),数据,生产消息的时间戳,重试次数。

如时间戳、重试次数、消息 ID 等消息元数据,随着消息传输给客户端,这样做简化了客户端,客户端不需要维护消息的状态。

消息会被序列化为字节流(依次以大端存储的方式保存消息 ID、时间戳、重试次数、数据),保存在了响应的 message 字段中。

客户端与服务器之间的请求和响应统一采用 Json 进行编码。

1
2
3
4
5
6
7
8
9
10
11
type Message struct {
ID iface.MessageID `json:"ID"`
Data []byte `json:"Data"`
Timestamp int64 `json:"Timestamp"`
Attempts uint16 `json:"Attempts"`

// 优先队列中使用到的数据结构
clientID uint64
pri int64
index int
}

通信协议

LMQ 中客户端与 lmqd 的通信协议如下:

  • 首先客户端进行连接。
  • 发送 SUB 命令订阅某个 Channel。
  • 发送 RDY 命令更新可以接收消息的数量。
  • LMQ 服务器会持续推送规定数量之内的消息。
  • 最后客户端返回 FIN 和 REQ 表示消息的接收状态。

nsq protocol

客户端流量控制

通过推送数据到客户端最大限度地提高性能和吞吐量,而不是等待客户端拉数据。LMQ 的客户端通过 RDY 状态表示自己准备好接受消息的数量,这是一种客户端流量控制的方法。

当客户端连接到 lmqd 和并订阅到一个 channel 时,客户端的 RDY 初始化为 0。当客户端的 RDY 状态被更新为大于零时,channel 才开始给这个客户端发送消息。

消息确认

客户端在收到消息后,需要发送 FIN 消息,表示消息已经成功接受。客户端也可以返回 REQ 消息,表示消息接受失败,此条消息重新进行排队。

当 lmqd 在超时时间内没有接受到 FIN 或者 REQ 消息,会自动判定客户端超时,这条消息会重新排队发送。

通过消息确认机制,可以保证消息确认被客户端收到,(在 lmqd 不崩溃的情况下)消息不会丢失。

本项目地址:LMQ

磁盘队列

每一个 topic 都会维护一个磁盘消息队列,每一个 channel 也会维护一个磁盘消息队列。当内存消息队列满了之后,新的消息就会存储在磁盘消息队列中。

在 lmqd 退出时消息的持久化也是依靠磁盘消息队列实现(将内存消息队列中的消息全部推入磁盘消息队列中,进行持久化存储)。

元数据

一个磁盘消息队列会维护多个文件,以 index 标识顺序。一个磁盘队列的核心元数据就是记录四个变量(元数据也会被持久化,以便标识下一次启动时的读取和写入位置):

  • 当前读取的文件号,当前读取的文件位置。
  • 当前写入的文件号,当前写入的文件位置。
阅读全文 »

本项目地址:LMQ

lmqd 中的元数据是指 lmqd 中的 Topic 和 Channel 信息

Topic

Topic 负责接受生产者的消息,并且将消息复制分发给每一个 channel 中。

数据结构

Topic 的结构如下,主要的属性有:

  • name:topic 的名称。
  • isTemporary:是否是临时的 Topic,如果名称带有 #tmp 则表明这是一个临时的 Topic。
    • 对于临时 Topic,backendQueue(磁盘队列)为 nil,所以超出内存队列长度的数据会被直接丢弃。
    • 若 channel 为空,则会立即删除这个 topic。
    • 一个临时的 topic 不会持久化到磁盘中。
  • channels:topic 下有多个 channel,保存所有在此 topic 下的 channel。
  • memoryMsgChan:内存消息队列。
  • backendMsgChan:磁盘消息队列。
  • deleteCallback:这个 topic 删除后的回调函数,主要用于删除 lmqd 中维护的 topic 信息。
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
type Topic struct {
lmqd iface.ILmqDaemon

name string
isTemporary bool // 标记是否是临时的topic
isPausing atomic.Bool // 标记是否已经暂停
isExiting atomic.Bool // 标记是否已经退出
channels map[string]iface.IChannel // 保存所有的channel字典
channelsLock sync.RWMutex // 控制对channel字典的互斥访问

guidFactory *GUIDFactory // message id 生成器

memoryMsgChan chan iface.IMessage // 内存chan
backendQueue backendqueue.BackendQueue // 当内存chan满了之后,将消息存入到后端队列中(持久化保存)

deleteCallback func(topic iface.ITopic)
deleter sync.Once

startChan chan struct{}
updateChan chan struct{}
pauseChan chan struct{}
closingChan chan struct{}
closedChan chan struct{}

messageCount atomic.Uint64
messageBytes atomic.Uint64
}

生产消息

通过 select,在内存队列中放入消息。如果内存队列已满,则会进入 default 分支,将消息送入磁盘消息队列中。

阅读全文 »

本项目地址:LMQ

LMQ 与 NSQ 的整体设计类似。

介绍

特性

LMQ 是分布式的消息队列,特性为:

  • 支持无单点故障的分布式拓扑。
  • 无缝的支持水平扩展,无缝的添加更多节点到集群。
  • 主要是在内存中传递消息,直接使用 TCP 协议而不是 HTTP 协议,所以性能可以保障。
  • 客户端发现的方式,通过查询 LmqLookup 找到生产者。

消息保证

消息不持久化机制

LMQ 支持内存队列磁盘队列,超过内存队列长度的消息会被存放在磁盘队列中。在内存队列中的消息可能因为宕机而丢失,存储在磁盘中的消息不会丢失。

可以通过设置内存队列长度为 0,所有的消息将会存储到磁盘,这样消息不会丢失

在正常推出的情况下,内存中的消息会被推送至磁盘队列中,在磁盘中保存持久化,元数据信息以 json 的格式进行持久化。

消息最少被投递一次

由于客户端超时导致的消息重新排队等原因,消息会被重复投递,消息通过 ID 区分,由客户端负责操作。

消息是无序的

LMQ 不保证消息的投递顺序和生产顺序是一致的。因为 LMQ 由内存队列、磁盘队列、重排队列混合组成,所以消息是无序的。

阅读全文 »