Clay 的技术空间

用进废退 | 艺不压身

SpringBoot 整合 gRPC

gRPC 的四种服务类型定义

  • 一个简单 RPC,客户端使用存根发送请求到服务器并等待响应返回,就像平常的函数调用一样。

    1
    rpc GetFeature(Point) returns (Feature) {}
  • 一个服务器端流式 RPC,客户端发送请求到服务器,拿到一个流去读取返回的消息序列。客户端读取返回的流,直到里面没有任何消息。通过在响应类型前插入 stream 关键字,可以指定一个服务器端的流方法。

    1
    rpc ListFeatures(Rectangle) returns (stream Feature) {}
  • 一个 客户端流式 RPC,客户端写入一个消息序列并将其发送到服务器,同样也是使用流。一旦客户端完成写入消息,它等待服务器完成读取返回它的响应。通过在请求类型前指定 stream 关键字来指定一个客户端的流方法。

    1
    rpc RecordRoute(stream Point) returns (RouteSummary) {}
  • 一个双向流式 RPC 是双方使用读写流去发送一个消息序列。两个流独立操作,因此客户端和服务器可以以任意喜欢的顺序读写:比如,服务器可以在写入响应前等待接收所有的客户端消息,或者可以交替地读取和写入消息,或者其他读写的组合,每个流中的消息顺序都会被预留。通过在请求和响应前加 stream 关键字去制定方法的类型。

    1
    rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
    阅读全文 »

前言

本文将介绍 gRPC、Protocol Buffers 的概念,同时会给出 Protocol Buffers 代码生成器的使用教程,还有编写第一个基于 gRPC 的服务提供者与服务消费者的示例程序。

相关站点

gRPC 简介

gRPC 是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供 C、Java、Go 语言版本,分别是:grpc、grpc-java、grpc-go,其中 C 版本支持 C、C++、Node.js、Python、Ruby、Objective-C、PHP、C#。gRPC 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特性。在 gRPC 里客户端应用可以像调用本地对象一样直接调用另一台不同的机器上服务端应用的方法,更容易地创建分布式应用和服务。与许多 RPC 系统类似,gRPC 也是基于以下理念:定义一个服务,指定其能够被远程调用的方法(包含参数和返回类型)。在服务端实现这个接口,并运行一个 gRPC 服务器来处理客户端调用。在客户端拥有一个存根能够像服务端一样的方法。值得说明的是,gRPC 客户端和服务端可以在多种环境中运行和交互,支持用任何 gRPC 支持的语言来编写,所以可以很容易地用 Java 创建一个 gRPC 服务端,用 Go、Python、Ruby 来创建客户端。

阅读全文 »

前言

集群模式

RabbitMQ 是用 Erang 开发的,集群模式分为两种普通模式镜像模式,可以说镜像模式普通模式的升级版,其中 RabbitMQ 默认使用的是 普通模式

  • 普通模式:
    以两个节点(rabbit01、rabbit02)为例来进行说明,rabbit01 和 rabbit02 两个节点仅有相同的元数据,即队列的结构,但消息实体只存在于其中一个节点 rabbit01(或者 rabbit02)中。当消息进入 rabbit01 节点的 Queue 后,consumer 从 rabbit02 节点消费时,RabbitMQ 会临时在 rabbit01、rabbit02 间进行消息传输,把 A 中的消息实体取出并经过 B 发送给 consumer。所以 consumer 应尽量连接每一个节点,从中取消息。即对于同一个逻辑队列,要在多个节点建立物理 Queue。否则无论 consumer 连 rabbit01 或 rabbit02,出口总在 rabbit01,会产生瓶颈。当 rabbit01 节点故障后,rabbit02 节点无法取到 rabbit01 节点中还未消费的消息实体。如果做了消息持久化,那么得等 rabbit01 节点恢复,然后才可被消费;如果没有持久化的话,就会产生消息丢失的现象。

  • 镜像模式:
    在普通模式的基础上,把需要的队列做成镜像队列,存在于多个节点,消息实体会主动在镜像节点间同步,而不是在客户端取数据时临时拉取,也就是说多少节点消息就会备份多少份。该模式带来的副作用也很明显,除了降低系统性能外,如果镜像队列数量过多,加之大量的消息进入,集群内部的网络带宽将会被这种同步通讯大大消耗掉,所以在对业务可靠性要求较高的场合中适用。由于镜像队列之间消息自动同步,且内部有选举 Master 机制,即使 Master 节点宕机也不会影响整个集群的使用,达到去中心化的目的,从而有效的防止消息丢失及服务不可用等问题

集群节点的区别

RabbitMQ 的集群节点分为磁盘节点、内存节点。RabbitMQ 支持消息的持久化,也就是数据写在磁盘上。在 RabbitMQ 集群中,必须至少有一个磁盘节点,否则队列元数据无法写入到集群中。当磁盘节点宕掉时,集群将无法写入新的队列元数据信息。如果 RabbitMQ 集群全部宕机,必须先启动磁盘节点,然后再启动内存节点。最合适的方案就是既有磁盘节点,又有内存节点,推荐 1 个 磁盘节点 + 2 个内存节点的集群搭建方式。

阅读全文 »

RabbitMQ 的非阻塞 I/O

NIO 通常也称非阻塞 I/O,包含三大核心部分:Channel(信道)、Buffer(缓冲区)和 Selector(选择器)。NIO 是基于 Channel 和 Buffer 进行操作的,数据总是从信道读取数据到缓冲区中,或者从缓冲区写入到信道中,而 Selector 则用于监听多个信道的时间(比如连接打开,数据到达等)。因此,单线程可以监听多个数据的信道。由于 RabbitMQ 采用类似 NIO(Non-blocking I/O)的做法,选择 TCP 连接复用,不仅可以减少性能开销,同时也便于管理。每个线程把持一个信道,所以信道复用了 Connection 的 TCP 连接。同时 RabbitMQ 可以确保每个线程的私密性,就像拥有独立的连接一样。当每个信道的流量不是很大时,复用单一的 Connection 可以在产生性能瓶颈的情况下有效地节省 TCP 连接资源。但是信道本身的流量很大时,这时候多个信道复用一个 Connection 就会产生性能瓶颈,进而使整体的流量被限制了。此时就需要开辟多个 Connection,将这些信道均摊到这些 Connection 中,至于这些相关的调优策略需要根据业务自身的实际情况进行调节。

RabbitMQ 的 ConnectionFactory、Connection、Channel

ConnectionFactory、Connection、Channel 都是 RabbitMQ 对外提供的 API 中最基本的对象。Connection 是 RabbitMQ 的 Socket 连接,它封装了 Socket 协议相关部分逻辑。ConnectionFactory 是客户端与 Broker 的 TCP 连接工厂,负责根据 URI 创建 Connection。Channel 是与 RabbitMQ 打交道的最重要的一个接口,大部分的业务操作是在 Channel 这个接口中完成的,包括定义 Queue、定义 Exchange、绑定 Queue、绑定 Exchange、发布消息等。如果每一次访问 RabbitMQ 都建立一个 Connection,在消息量大的时候建立 TCP Connection 的开销将是巨大的,效率也较低。Channel 是在 Connection 内部建立的逻辑连接,如果应用程序支持多线程,通常每个 Thread 创建单独的 Channel 进行通讯,AMQP Method 包含了 Channel ID 帮助客户端和 Message Broker 识别 Channel,所以 Channel 之间是完全隔离的。Channel 作为轻量级的 Connection 极大减少了操作系统建立 TCP Connection 的开销。

阅读全文 »

相关站点

RabbitMQ 基础概念

AMQP(Advanced Message Queuing Protocol)高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计。消息中间件主要用于组件之间的解耦,消息的发送者无需知道消息使用者的存在,反之亦然。AMQP 的主要特征是面向消息、队列、路由(包括点对点和发布 / 订阅)、可靠性、安全。RabbitMQ 是一个开源的 AMQP 标准实现,服务器端用 Erlang 语言编写,支持多种客户端,如:Python、Ruby、C#、Java、PHP、GO、JavaScript 等。RabbitMQ 用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性、灵活的路由、集群、事务、高可用的队列、消息排序、问题追踪、可视化管理工具、插件系统等方面表现不俗。

RabbitMQ 的用户角色分类

  • 超级管理员 (administrator),可登陆管理控制台,可查看所有的信息,并且可以对用户,策略 (policy) 进行操作
  • 监控者 (monitoring),可登陆管理控制台,同时可以查看 rabbitmq 节点的相关信息 (进程数,内存使用情况,磁盘使用情况等)
  • 策略制定者 (policymaker),可登陆管理控制台,同时可以对 policy 进行管理。但无法查看节点的相关信息,与 administrator 的对比,administrator 能看到节点信息
  • 普通管理者 (management),仅可登陆管理控制台,无法看到节点信息,也无法对策略进行管理
  • 其他,无法登陆管理控制台,通常就是普通的生产者和消费者
阅读全文 »

微服务与微服务架构

微服务的概述

微服务理论的提出者马丁。福勒(Martin Fowler) 在其博客中详细描述了什么是微服务。微服务强调的是服务的大小,它关注的是某一个点,是具体解决某一个问题 / 提供落地对应服务的一个服务应用;狭意的看,可以看作 Eclipse 里面的一个个微服务工程 / 或者 Module。

微服务架构的概述

微服务架构是一种架构模式或者说是一种架构风格,它提倡将单一应用程序划分为一组小服务,每个服务运行在自己的独立进程中,服务间通信采用轻量级通信机制 (通常是基于 HTTP 的 RESTful API)。每个服务都围绕着具体业务进行构建,并且能够被独立地部署到生产环境、类生产环境等。另外,应该尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建,可以有一个非常轻量级的集中式管理来协调这些服务,可以使用不同的语言来编写服务,也可以使用不同的数据存储技术。

阅读全文 »

@RequestBody 注解抛出异常

问题描述:使用 @RequestBody 注解时,抛出异常信息 “Required request body is missing”

采用 SSM 框架,前端将参数传递给后端,SpringMVC 可以通过注解 @RequestBody 将传递参数绑定在 Controller 的方法参数中。此时必须注意,当请求方法声明为 GET 和 DELETE 的时候,HTTP 请求规范里规定是不会有 RequestBody 的,只有请求方法声明为 POST 和 PUT 的时候才有,因此 @RequestBody 不适用于 GET 与 DELETE 方法。还有如果请求方法声明为 GET、DELETE,那么 SpringMVC 可以直接将传递参数绑定在方法的参数中,如果请求方法声明为 POST、PUT,则必须使用注解 @RequestBody 修饰 Controller 中的方法参数,否则无法获取前端传递过来的参数值。正确的使用方法如下:

阅读全文 »

前言

特别注意

RabbitMQ 的数据库名称规则是 NODENAME@hostname,由于 Docker 每次从 Docker Image 启动容器的时候会自动生成 hostname,这样一来之前保存在主机上的数据库就会没用了,包括之前创建的用户也会没有了。所以在创建容器的时候必须指定 hostname,比如 --hostname=my-rabbit,这样 Docker 环境启动后 RabbitMQ 就会一直读取固定目录中的数据。

阅读全文 »