前面花了一段时间去学习SpringCloud的相关知识,主要是理解微服务的概念并使用SpringCloud的一系列组件实现微服务落地。学习这些组件本身是简单的,跟着操作一遍基本就会了,这也得益于Springboot给我们带来了很多便利。实际的应用中也许还会碰到一些坑,但只要我们掌握基本的原理就能够解决。
前面也讲了微服务的解决方案有两个,一个是SpringCloud,另外一个就是Dubbo+Zookeeper,下面我们来学习Dubbo+Zookeeper实现微服务。
在学习微服务的第一篇中,理解了微服务的概念,比较了微服务与单体应用之前的优势和劣势,讲了要实现微服务主要的技术点,最重要的两块在于服务之间的通信和服务治理。
Dubbo+Zookeeper要实现微服务,就必须解决这两个技术点,Dubbo是一个RPC通信框架,它可以实现服务之间的通信。ZooKeeper 是一种分布式协调服务,用于管理大型主机。在分布式环境中协调和管理服务是一个复杂的过程。
一、分布式协调技术上面说Zookeeper是一个分布式协调技术,那么我们就得先来学习什么是分布式协调技术。分布式协调技术主要用来解决分布式环境当中多个进程之间的同步控制,让他们有序的去访问某种临界资源,防止造成"脏数据"的后果。
首先,要明白我们为什么需要分布式锁,一个简单的例子,一般系统上都有一些定时任务,比如做一些数据的清算,如果我们部署了多台服务器,那在这个时候每台服务器都会执行这个定时任务,如果没有一个锁机制,那按照道理来说,这个定时任务就会被执行多次,这样就非常有可能出现脏数据。
这里指的是一个定时任务,既然是定时任务,那么它必然会是同一个时刻进入,这个不需要高并发,我们也需要考虑。还有一种情况是高并发情况下,在分布式环境中,很大概率会存在多个节点上的进程同时访问某一个方法,而很多时候,我们需要保证一个方法在同一时间内只能被同一个线程执行,在单机环境中,Java中其实提供了很多并发处理相关的API,但是这些API在分布式场景中就无能为力了。也就是说单纯的Java Api并不能提供分布式锁的能力。所以针对分布式锁的实现目前有多种方案。
我们需要的分布式锁应该是怎么样的?(这里以方法锁为例,资源锁同理)
可以保证在分布式部署的应用集群中,同一个方法在同一时间只能被一台机器上的一个线程执行。
这把锁要是一把可重入锁(避免死锁)
这把锁最好是一把阻塞锁(根据业务需求考虑要不要这条)
有高可用的获取锁和释放锁功能
获取锁和释放锁的性能要好
实现分布式锁有几种方案:
Memcached:利用 Memcached 的 add 命令。此命令是原子性操作,只有在 key 不存在的情况下,才能 add 成功,也就意味着线程得到了锁。
Redis:和 Memcached 的方式类似,利用 Redis 的 setnx 命令。此命令同样是原子性操作,只有在 key 不存在的情况下,才能 set 成功。
Zookeeper:利用 Zookeeper 的顺序临时节点,来实现分布式锁和等待队列。Zookeeper 设计的初衷,就是为了实现分布式锁服务的。
Chubby:Google 公司实现的粗粒度分布式锁服务,底层利用了 Paxos 一致性算法。
二、分布式锁实现的基本原理要实现锁,那最基本的功能就有三个:加锁,解锁,锁超时,我们用redis的实现方式来简单的介绍下分布式锁的基本原理,以下代码都为伪代码。
2.1 加锁redis实现加锁最简单的操作就是是使用 setnx 命令,其中的key可以根据业务名称来命名,基本模式是命名空间+对应的参数,比如我们要锁住某个商品库存,那我们可以用库存的id作为参数进行加锁,其实这里我们在不同的方法上可以加上相同的锁,比如,有两个方法都需要对库存进行处理,虽然他们并不是一个方法,但我们用同一个命名空间和参数也可以锁住。
setnx(lock_sale_商品ID,1)