分布式(三)

三、API 网关详解

1. 网关及作用

主要功能:请求过滤

网关可以为我们提供请求转发、安全认证(身份/权限认证)、流量控制、负载均衡、降级熔断、日志、监控等功能。

在这里插入图片描述

2. 常见的网关系统

2.1 Netflix Zuul

(1)Zuul 是 Netflix 开发的一款提供动态路由、监控、弹性、安全的网关服务。

(2)Zuul 主要通过过滤器(类似于 AOP)来过滤请求,从而实现网关必备的各种功能。
在这里插入图片描述
(3)可以自定义过滤器来处理请求,并且,Zuul 生态本身就有很多现成的过滤器供我们使用。
如限流可以直接用国外朋友写的 spring-cloud-zuul-ratelimit (这里只是举例说明,一般是配合 hystrix 来做限流):

(4)Zuul 1.x 基于同步 IO,性能较差。Zuul 2.x 基于 Netty 实现了异步 IO,性能得到了大幅改进。

链接:
官方 Wiki
Github 地址

2.2 Spring Cloud Gateway

2.2.1 简介

(1)为了提升网关的性能,SpringCloud Gateway 基于 Spring WebFlux 。
Spring WebFlux 使用 Reactor 库来实现响应式编程模型,底层基于 Netty 实现异步 IO。

(2)不仅提供统一的路由方式,并且基于 Filter 链的方式提供了网关基本的功能
例如:安全,监控/指标,和限流。

(3)Spring Cloud Gateway 和 Zuul 2.x 的差别不大,也是通过过滤器来处理请求。
不过,目前更加推荐使用 Spring Cloud Gateway 而非 Zuul,Spring Cloud 生态对其支持更加友好。

链接:
官网
Github 地址

原理及应用

详见我另一篇博客,链接:
SpringCloud之Gateway

2.3 Kong

(1)Kong 是一款基于 OpenResty 的高性能、云原生、可扩展的网关系统。

OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。

用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。

(2)Kong 提供了插件机制来扩展其功能。比如、在服务上启用 Zipkin 插件

官网
Github 地址

2.4 APISIX

(1)APISIX 是一款基于 Nginx 和 etcd 的高性能、云原生、可扩展的网关系统。

(2)etcd是使用 Go 语言开发的一个开源的、高可用的分布式 key-value 存储系统,使用 Raft 协议做分布式共识。

(3)与传统 API 网关相比,APISIX 具有动态路由和插件热加载,特别适合微服务系统下的 API 管理。

(4)并且,APISIX 与 SkyWalking(分布式链路追踪系统)、Zipkin(分布式链路追踪系统)、Prometheus(监控系统) 等 DevOps 生态工具对接都十分方便。

在这里插入图片描述
(5)作为 NGINX 和 Kong 的替代项目,APISIX 目前已经是 Apache 顶级开源项目,并且是最快毕业的国产开源项目。

国内目前已经有很多知名企业(比如金山、有赞、爱奇艺、腾讯、贝壳)使用 APISIX 处理核心的业务流量。

APISIX 已经生产可用,功能、性能、架构全面优于 Kong。

链接:
官网
Github 地址

2.5 Shenyu

(1)Shenyu 是一款基于 WebFlux 的可扩展、高性能、响应式网关,Apache 顶级开源项目。
在这里插入图片描述
(2)Shenyu 通过插件扩展功能,插件是 ShenYu 的灵魂。
并且插件也是可扩展和热插拔的。不同的插件实现不同的功能。

Shenyu 自带了诸如限流、熔断、转发 、重写、重定向、和路由监控等插件。

链接:
官网
Github 地址



四、分布式ID详解

ID 就是数据的唯一标识。

分布式 ID 是分布式系统下的 ID。

1.分布式ID要满足的要求

在这里插入图片描述

1.1 最基本

(1)全局唯一

(2)高性能
生成速度要快,对本地资源消耗要小。

(3)高可用
生成分布式 ID 的服务要保证可用性无限接近于 100%。

(4)方便易用
拿来即用,使用方便,快速接入!

1.2 一个比较好的分布式 ID 还应保证如下:

(1)安全
不包含敏感信息。

(2)有序递增

有序性可以提升数据库写入速度;

可以直接通过 ID 来进行排序。

(3)有具体的业务含义
如果能有具体的业务含义,可以让定位问题以及开发更透明化(通过 ID 就能确定是哪个业务)。

(4)独立部署
也就是分布式系统单独有一个发号服务器,专门用来生成分布式 ID。

这样就生成 ID 的服务可以和业务相关的服务解耦。



2.分布式 ID 常见解决方案

2.1 数据库

2.1.1 数据库主键自增

通过关系型数据库的自增主键产生来唯一的 ID。

2.1.1.1 步骤

(1)创建一个数据库表

CREATE TABLE `sequence_id` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `stub` char(10) NOT NULL DEFAULT '',
  PRIMARY KEY (`id`),
  UNIQUE KEY `stub` (`stub`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

stub 字段无意义,只是为了占位,便于我们插入或者修改数据。并且,给 stub 字段创建了唯一索引,保证其唯一性。

(2)通过 replace into (而非insert into)来插入数据

BEGIN;
REPLACE INTO sequence_id (stub) VALUES ('stub');
SELECT LAST_INSERT_ID();
COMMIT;
2.1.1.1 优缺点

(1)优点
实现起来比较简单、ID 有序递增、存储消耗空间小

(2)缺点
支持的并发量不大

存在数据库单点问题(可以使用数据库集群解决,不过增加了复杂度)

ID 没有具体业务含义

安全问题(比如根据订单 ID 的递增规律就能推算出每天的订单量,商业机密啊! )

每次获取 ID 都要访问一次数据库(增加了对数据库的压力,获取速度也慢)


2.1.2 数据库号段模式
2.1.2.1 简介

(1)可以批量获取(不用每次都访问数据库),然后存在在内存里面,需要用到的时候,直接从内存里面取。

(2)应用公司
滴滴开源的Tinyid,不过还使用了双号段缓存、增加多 db 支持等方式来进一步优化。

2.1.2.2 步骤

(1)创建一个数据库表

CREATE TABLE `sequence_id_generator` (
  `id` int(10) NOT NULL,
  `current_max_id` bigint(20) NOT NULL COMMENT '当前最大id',
  `step` int(10) NOT NULL COMMENT '号段的长度',
  `version` int(20) NOT NULL COMMENT '版本号',
  `biz_type`    int(20) NOT NULL COMMENT '业务类型',
   PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

current_max_id 字段和step字段主要用于获取批量 ID,获取的批量 id 为: current_max_id ~ current_max_id+step。

version 字段主要用于解决并发问题(乐观锁),biz_type 主要用于表示业务类型。

在这里插入图片描述

(2)先插入一行数据

INSERT INTO `sequence_id_generator` (`id`, `current_max_id`, `step`, `version`, `biz_type`)
VALUES
	(1, 0, 100, 0, 101);

(3)通过 SELECT 获取指定业务下的批量唯一 ID

SELECT `current_max_id`, `step`,`version` FROM `sequence_id_generator` where `biz_type` = 101

// 查询结果如下:
id	current_max_id	step	version	biz_type
1	0	100	0	101

(4)不够用的话,更新之后重新 SELECT 即可

UPDATE sequence_id_generator SET current_max_id = 0+100, version=version+1 WHERE version = 0  AND `biz_type` = 101
SELECT `current_max_id`, `step`,`version` FROM `sequence_id_generator` where `biz_type` = 101

// 以上结果如下:
id	current_max_id	step	version	biz_type
1	100	100	1	101

2.1.2.2 优缺点

相比于数据库主键自增的方式,数据库的号段模式对于数据库的访问次数更少,数据库压力更小。

另外,为了避免单点问题,你可以从使用主从模式来提高可用性。

(1)优点
ID 有序递增、存储消耗空间小

(2)缺点
存在数据库单点问题(可以使用数据库集群解决,不过增加了复杂度)

ID 没有具体业务含义

安全问题(比如根据订单 ID 的递增规律就能推算出每天的订单量,商业机密啊! )


2.1.3 NoSQL

一般使用 Redis

2.1.3.1 Redis

(1)通过 Redis 的 incr 命令即可实现对 id 原子顺序递增

127.0.0.1:6379> set sequence_id_biz_type 1
OK
127.0.0.1:6379> incr sequence_id_biz_type
(integer) 2
127.0.0.1:6379> get sequence_id_biz_type
"2"

(2)为了提高可用性和并发,我们可以使用 Redis Cluster(3.0+版本)
或者使用开源的 Redis 集群方案Codis (大规模集群比如上百个节点的时候比较推荐)。

(3)Redis 基于内存,我们需要持久化数据,避免重启机器或者机器故障后数据丢失。
快照(snapshotting,RDB)、只追加文件(append-only file, AOF)、 RDB 和 AOF 的混合持久化(4.0 +版本)

有关Redis实践,详见我另一篇博客,链接:
Redis主从复制与哨兵模式

(4)Redis 方案的优缺点
<1> 优点 : 性能不错并且生成的 ID 是有序递增的

<2> 缺点 : 和数据库主键自增方案的缺点类似

2.1.3.2 MongoDB ObjectId

(1)MongoDB ObjectId 一共需要 12 个字节存储:
0~3:时间戳

3~6: 代表机器 ID

7~8:机器进程 ID

9~11 :自增值

(2)优缺点
<1> 优点 : 性能不错并且生成的 ID 是有序递增的

<2> 缺点 :
需要解决重复 ID 问题(当机器时间不对的情况下,可能导致会产生重复 ID)

有安全性问题(ID 生成有规律性)


2.2 算法

2.2.1 UUID

Universally Unique Identifier(通用唯一标识符)

UUID 包含 32 个 16 进制数字(8-4-4-4-12)。

UUID 可以保证唯一性,因为其生成规则包括 MAC 地址、时间戳、名字空间(Namespace)、随机或伪随机数、时序等元素,计算机基于这些规则生成的 UUID 是肯定不会重复的。

2.2.1.1 版本

(1)版本1
UUID 是根据时间和节点 ID(通常是 MAC 地址)生成
在这里插入图片描述

(2)版本2
UUID 是根据标识符(通常是组或用户 ID)、时间和节点 ID 生成

(3)版本3、5
确定性 UUID 通过散列(hashing)名字空间(namespace)标识符和名称生成;

(4)版本4(JDK默认)
UUID 使用随机性或伪随机性生成。

2.2.1.2 为什么不合适作为数据库主键

(1)数据库主键要尽量越短越好,而 UUID 的消耗的存储空间比较大(32 个字符串,128 位)。

(2)UUID 是无顺序的,InnoDB 引擎下,数据库主键的无序性会严重影响数据库性能。

2.2.1.2 优缺点

(1)优点
生成速度比较快、简单易用

(1)缺点
存储消耗空间大(32 个字符串,128 位)

不安全(基于 MAC 地址生成 UUID 的算法会造成 MAC 地址泄露)

无序(非自增)

没有具体业务含义

需要解决重复 ID 问题(当机器时间不对的情况下,可能导致会产生重复 ID)

2.2.2 Snowflake(雪花算法)

Snowflake 是 Twitter 开源的分布式 ID 生成算法。

2.2.2.1 组成

Snowflake 由 64 bit 的二进制数字组成,这 64bit 的二进制被分成了以下部分:

(1)第 0 位
符号位(标识正负),始终为 0,没有用,不用管。

(2)第 1~41 位
一共 41 位,用来表示时间戳,单位是毫秒,可以支撑 2 ^41 毫秒(约 69 年)

(3)第 42~52 位
一共 10 位,一般来说,前 5 位表示机房 ID,后 5 位表示机器 ID(实际项目中可以根据实际情况调整)。这样就可以区分不同集群/机房的节点。

(4)第 53~64 位
一共 12 位,用来表示序列号。 序列号为自增值,代表单台机器每毫秒能够产生的最大 ID 数(2^12 = 4096),也就是说单台机器每毫秒最多可以生成 4096 个 唯一 ID。

在这里插入图片描述

2.2.2.2 应用

(1)在 Snowflake 算法生成的 ID 中加入业务类型信息

(2)开源实现及优化:美团 的 Leaf、百度的 UidGenerator

2.2.2.3 优缺点

(1)优点
生成速度比较快

生成的 ID 有序递增
比较灵活(可以对 Snowflake 算法进行简单的改造比如加入业务 ID)

(2)缺点
需要解决重复 ID 问题(依赖时间,当机器时间不对的情况下,可能导致会产生重复 ID)


2.3 开源框架

2.3.1 UidGenerator(百度)

UidGenerator 是百度开源的一款基于 Snowflake(雪花算法)的唯一 ID 生成器。

在这里插入图片描述

2.3.2 Leaf(美团)

Leaf 是美团开源的一个分布式 ID 解决方案 。

在这里插入图片描述

(1)为了解决美团各个业务线生成分布式 ID 的方法多种多样以及不可靠的问题。

(2) 号段模式 和 Snowflake(雪花算法) 这两种模式来生成分布式 ID

(3)它支持双号段,还解决了雪花 ID 系统时钟回拨问题。
不过,时钟问题的解决需要弱依赖于 Zookeeper 。

(4)Leaf 对原有的号段模式进行改进。
比如它这里增加了双号段避免获取 DB 在获取号段的时候阻塞请求获取 ID 的线程。

即就是我一个号段还没用完之前,我自己就主动提前去获取下一个号段

在这里插入图片描述

2.3.2 Tinyid(滴滴)

Tinyid 是滴滴开源的一款基于数据库号段模式的唯一 ID 生成器。

(1)双号段缓存
为了避免在获取新号段的情况下,程序获取唯一 ID 的速度比较慢。

Tinyid 中的号段在用到一定程度的时候,就会去异步加载下一个号段,保证内存中始终有可用号段。

(2)增加多db支持
支持多个 DB,并且,每个 DB 都能生成唯一 ID,提高了可用性。

(3)增加tinyid-client
纯本地操作,无 HTTP 请求消耗,性能和可用性都有很大提升。

2.3 其他

如: ZooKeeper 这类中间件也可以帮助我们生成唯一 ID

**总结:**一定要结合实际项目来选择最适合自己的方案。



上一篇跳转—分布式(二)                 下一篇跳转—分布式(四)


本篇文章主要参考链接如下:

参考链接1-JavaGuide


持续更新中…

随心所往,看见未来。Follow your heart,see light!

欢迎点赞、关注、留言,一起学习、交流!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值