赞
踩
单体、分布式、微服务小口诀:
厨房里一开始只有一个厨师,这个厨师既要自己洗菜,切菜,还要自己炒菜,这叫做单体
;
老板又请了一个厨师,这个厨师同样既要自己洗菜,切菜,还要自己炒菜,两个厨师之间的关系叫做分布式
(职责一样,重在对硬件资源的横向拓展应用);
老板又分别请了一个洗菜的阿姨和切菜的师傅,以后厨师只需要专注于炒菜了。洗菜阿姨,切菜师傅,炒菜厨师之间的关系就是微服务
(职责不同,专注于各自的服务)
说到分布式锁,这里其实有2个概念,即【分布式 + 锁】。分布式这个概念我们可以看看【前置知识】;至于锁嘛,第一概念当然是JUC中的锁了。如:Sychronized和ReentractLock。但是,这些作为JVM级别的锁,只能应用在同一个进程中,不同线程的竞争中,没办法满足分布式(多进程)的使用场景、于是,就需要一种更加高级的锁机制来处理多进程之间的数据同步问题,这种机制就是:分布式锁。
目前分布式锁,比较成熟、主流的方案:
对Redis分布式锁比较熟悉的同学估计会想:Redis不是最优方案了吗,还搞什么劳什子的ZK分布式锁啊?只能说各有各的优点。Redis分布式锁在高可用上确实不错,但是因为没满足强一致性,所以,如果出现宕机,确实是有可能会出现最长30秒无法解锁的问题。但是在ZK中就不会出现,这是因为ZK的强一致性和监听机制带来的好处。
可以利用数据库的唯一索引来实现,唯一索引天然具有排他性
但还是那句话,有Redis分布式锁了,没必要使用这个数据库的分布式锁(我在上古C语言项目使用过,甚至还用过Linux文件系统来做分布式锁的)。
使用临时 znode 来表示获取锁的请求,创建 znode成功的用户拿到锁。
上述这种方案虽然能实现,但其实会有一个问题。那就是:
使用临时有序znode来表示获取锁的请求,创建后,znode序号最小的用户成功拿到锁。下面是一种公平锁的实现的实现原理图:
我们可以看看上面的流程图,它通过,每次让节点监听比自己小1的节点的删除事件,来让自己实现排队等待唤醒的机制。
不过,上述的流程已经不需要我们我们自己去写了,之前介绍过的Curator
客户端,已经提供了相应的API了。
它的大概流程如下:
简单的代码使用案例如下:
public class CuratorLockTest implements Runnable { final static CuratorFramework client = CuratorFrameworkFactory.builder().connectString("localhost:2181") .retryPolicy(new ExponentialBackoffRetry(100, 1)).build(); private OrderCodeGenerator orderCodeGenerator = new OrderCodeGenerator(); // 可重入互斥锁 final InterProcessMutex lock = new InterProcessMutex(client, "/curator_lock"); public static void main(String[] args) throws InterruptedException { client.start(); for (int i = 0; i < 30; i++) { new Thread(new CuratorLockTest()).start(); } Thread.currentThread().join(); } @Override public void run() { // 加锁 lock.acquire(); try { String orderCode = orderCodeGenerator.getOrderCode(); System.out.println("生成订单号 " + orderCode); } catch (Exception e) { e.printStackTrace(); } finally { try { // 释放锁 lock.release(); } catch (Exception e) { e.printStackTrace(); } } } } /** * 订单号生成工具类 * 由于++count非原子的,所以是线程不安全的 * 没有锁的话,肯定会出现订单号重复的现象 */ public class OrderCodeGenerator { private static int count = 0; public String getOrderCode(){ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddhhmmss"); return simpleDateFormat.format(new Date()) + "-" + ++count; } }
优点:ZooKeeper分布式锁(如InterProcessMutex),具备高可用、可重入、阻塞锁特性,可解决失效死锁问题,使用起来也较为简单
缺点:因为需要频繁的创建和删除节点,性能上不如Redis
在高性能、高并发的应用场景下,不建议使用ZooKeeper的分布式锁。而由于ZooKeeper的高可靠性,因此在并发量不是太高的应用场景中,还是推荐使用ZooKeeper的分布式锁。
基于ZooKeeper本身的线性写、监听等特性可以实现服务注册中心。
Q1:什么是服务注册与发现?
在分布式架构中,由于微服务实例数量较多,其 IP 地址和端口号会经常变化,因此需要一个机制来自动维护微服务的实例信息,实现微服务之间的通讯。服务注册发现机制就是解决这个问题的机制。
服务提供者会将自己的实例信息注册到服务注册中心,服务消费者通过服务注册中心获取服务提供者的实例信息进行通讯。服务消费者和服务提供者之间的通讯不需要知道对方的实际 IP 地址和端口号,只需要通过服务名即可。
优点:(其实就是ZK本身的优点)
缺点:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。