分布式锁
必须满足的要求
- 安全性(Safety):在任意时刻,只有一个客户端可以获得锁(排他性)。
- 避免死锁:客户端最终一定可以获得锁,即使锁住某个资源的客户端在释放锁之前崩溃或者网络不可达。
- 容错性:只要锁服务集群中的大部分节点存活,Client 就可以进行加锁解锁操作。
Redis 实现分布式锁的 demo
- 加锁:需要设置过期时间
SET resource_name my_random_value NX PX 30000
- 解锁:需要将查询 + 删除作为一个原子操作执行。即为了防止其他客户端误删正常客户端的锁。
if redis.call("get",KEYS[1]) == ARGV[1] then
return redis.call("del",KEYS[1])
else
return 0
end
分布式锁的问题
例如 Redis 类似锁实现方案中,为了防止死锁,就是加了过期时间,但是如果获得锁的客户端由于某种意外执行时间超过了这个过期时间,就会导致锁提前释放,被其他客户端抢占执行,这样子就可能存在两个并行执行的场景。
如果客户端在这个处理过程中,有些数据库的场景,可能就会导致业务产生某种问题。
那如何解决这个问题呢?
引入 fence(栅栏)技术。一般来说,这就是乐观锁机制,需要一个版本号排他。
分布式锁设计的重点
如果你引入了数据库来做乐观锁,那分布式锁还有存在的价值吗?理论上不考虑性能上的问题的话,乐观锁或者 CAS 其实就已经涵盖了分布式锁的概念了。
所以什么情况下才需要引入分布式锁非常重要 —— 用来不同进程间的同步或是互斥的需要引入。
配置中心
这个取决于规模,技术不是难点,难点在于规范和开发者体验
边车模式
我们不需要在服务中实现控制面上的东西,如监视、日志记录、限流、熔断、服务注册、协议适配转换等这些属于控制面上的东西,而只需要专注地做好和业务逻辑相关的代码,然后,由“边车”来实现这些与业务逻辑没有关系的控制功能。
实现方式:
- 一种是通过 SDK、Lib 或 Framework 软件包方式,在开发时与真实的应用服务集成起来。
- 另一种是通过像 Sidecar 这样的方式,在运维时与真实的应用服务集成起来。
场景分析:
不适合的场景:
- 架构并不复杂的时候,不需要使用这个模式,直接使用 API Gateway 或者 Nginx 和 HAProxy 等即可。
- 服务间的协议不标准且无法转换。
- 不需要分布式的架构。
适合的场景:
- 一个比较明显的场景是对老应用系统的改造和扩展。
- 另一个是对由多种语言混合出来的分布式服务系统进行管理和扩展。
- 其中的应用服务由不同的供应商提供。把控制和逻辑分离,标准化控制面上的动作和技术,从而提高系统整体的稳定性和可用性。
- 也有利于分工——并不是所有的程序员都可以做好控制面上的开发的。
服务网格
Service Mesh 这个服务网络专注于处理服务和服务间的通讯。其主要负责构造一个稳定可靠的服务通讯的基础设施,并让整个架构更为的先进和 Cloud Native。在工程中,Service Mesh 基本来说是一组轻量级的服务代理和应用逻辑的服务在一起,并且对于应用服务是透明的。
- Service Mesh 是一个基础设施。
- Service Mesh 是一个轻量的服务通讯的网络代理。
- Service Mesh 对于应用服务来说是透明无侵入的。
- Service Mesh 用于解耦和分离分布式系统架构中控制层面上的东西。
Service Mesh 相关的开源软件
- Istio 业界标准
- Linkerd 依托JVM,性能相对来说较低
- Conduit 新生儿
copy 图,为 istio 的简单架构图,就是代理 + 控制面组成。
Service Mesh 的设计重点
由于所有服务都要经过 Mesh,这个一旦挂了,系统就挂了,所以必须要有高可靠的考量。这边笔者的意思主要还是多副本冗余的方式。
服务集群需要有集群级别的 Mesh 组,每个服务节点自身也需要单独的 Mesh,即使服务自身的挂掉,也至少有集群级别的可以进行路由。
网关模式
Gateway 是一个服务器,也可以说是进入系统的唯一节点。这跟面向对象设计模式中的 Facade 模式很像。Gateway 封装内部系统的架构,并且提供 API 给各个客户端。它还可能有其他功能,如授权、监控、负载均衡、缓存、熔断、降级、限流、请求分片和管理、静态响应处理,等等。
Gateway、Sidecar 和 Service Mesh
三种设计模式的特点、场景和区别。
- Sidecar 的方式主要是用来改造已有服务。通过 Sidecar 的方式,我们可以适配应用服务,成为应用服务进出请求的代理。这样,我们就可以干很多对于业务方完全透明的事情了。
- Sidecar 在架构中越来越多时,需要我们对 Sidecar 进行统一的管理。于是,我们为 Sidecar 增加了一个全局的中心控制器,就出现了我们的 Service Mesh。在中心控制器出现以后,我们发现,可以把非业务功能的东西全部实现在 Sidecar 和 Controller 中,于是就成了一个网格。业务方只需要把服务往这个网格中一放就好了,与其它服务的通讯、服务的弹力等都不用管了,像一个服务的 PaaS 平台。
- 然而 Service Mesh 的架构和部署太过于复杂,为了简化这个架构的复杂度,可以是用 Gateway 来简化。而且 Gateway 只负责进入的请求,不像 Sidecar 还需要负责对外的请求。因为 Gateway 可以把一组服务给聚合起来,所以服务对外的请求可以交给对方服务的 Gateway。于是,我们只需要用一个负责进入请求的 Gateway 来简化需要同时负责进出请求的 Sidecar 的复杂度。
部署升级策略
- 停机部署(Big Bang / Recreate): 把现有版本的服务停机,然后部署新的版本。
- 蓝绿部署(Blue/Green /Stage):部署好新版本后,把流量从老服务那边切过来。
- 滚动部署(Rolling Update / Ramped): 一点一点地升级现有的服务。
- 灰度部署(Canary):把一部分用户切到新版本上来,然后看一下有没有问题。如果没有问题就继续扩大升级,直到全部升级完成。
- AB 测试(A/B Testing):同时上线两个版本,然后做相关的比较