为什么需要使用分布式:
随着业务的发展和用户流量的上升,对互联网系统或者服务程序则提出了新的挑战,其中,高吞吐、高并发、强扩展、 灵活部署及低延迟等俨然成为急需解决的需求!为此,作为枢纽的中间件也从“集中式”发展为“分布式”, 如基于Redis的分布式缓存、基于RabbitMQ的分布式消息中间件、基于Elasticsearch的分布式全文搜索引擎、基于ZooKeeper的分布式锁等。
分布式发展历程:
- 单点集中式Web应用
- 应用与文件服务及数据库单独拆分
- 引入缓存与集群,改善系统整体性能
- 数据库读写分离,并提供反向代理及CDN加速访问服务
- 分布式文件系统与分布式数据库
分布式系统特点:
- 内聚性和透明性
- 可扩展性
- 可用与可靠性
- 高性能
- 一致性
分布式系统常见问题:
- 网络并没有那么可靠
- 节点故障无法避免
集群、共享资源:
- 集群:为了应对某些业务场景下产生的高并发请求,通常一个子系统会部署多份实例,并采用某种均衡机制“分摊”处理前端用户的请求,此种方式俗称集群
- 共享资源:可以被多个线程或进程同时访问并进行操作的数据或者代码块
- 分布式环境下资源共享将不再是传统的线程共享,而是跨JVM进程之间资源的共享
中间件:
- redis 支持多种数据类型,包括字符串、哈希表、列表、集合、有序集合和位图等
- redisson Redisson的出现使得原本作为协调单机多线程并发程序的工具包,获得了协调分布式多机多线程并发系统的能力,大大降低了设计和研发大规模分布式系统的难度,同时也简化了分布式环境中程序相互之间的协作
- RabbitMQ 可用于实现消息异步分发、模块解耦、接口限流等功能
- ZooKeeper ZooKeeper是一个开源的分布式应用程序协调服务,可以为分布式应用提供一致性服务
微服务:
SpringBoot优势:
- 快速整合第三方框架(直接引用内置的Start Jar)
- 运行部署方便(内置tomcat)
- 开发便捷(不需要繁琐的文件配置)
分布式锁:
- 分布式锁:
分布式锁,也是一种锁机制,只不过是专门应对“分布式”的环境而出现的,它并不是一种全新的中间件或者组件,而只是一种机制,一种实现方式, 甚至可以说是一种解决方案。它指的是在分布式部署的环境下,通过锁机制让多个客户端或者多个服务进程互斥地对共享资源进行访问, 从而避免出现并发安全、数据不一致等问题。
- 分布式锁的特点:
- 排它性:需要保证分布式部署、服务集群部署的环境下,被共享的资源如数据或者代码块在同一时间内只能被一台机器上的一个线程执行
- 避免死锁:指的是当前线程获取到锁后,经过一段有限的时间,一定要释放锁
- 高可用:指的是获取或者释放锁的机制必须高可用而且性能极佳
- 可重入:即当前机器的当前线程在彼时如果没有获取到锁,那么在等待一定的时间后一定要保证可以再被获取到
- 公平锁(可选):这并非硬性的要求,指的是不同机器的不同线程在获取锁时最好保证几率是一样的,即应当保证来自不同机器的并发线程可以公平获取到锁。
- 分布式锁的实现方式:
1、 基于数据库级别的
- 乐观锁:主要是通过在查询、操作共享数据记录时带上一个标识字段version,通过version来控制每次对数据记录执行的更新操作
- 排它锁:在这里以MySQL的InnoDB引擎为例,它主要是通过在查询共享的数据记录时加上For Update字眼,表示该共享的数据记录已经被当前线程锁住了 (行级别锁、表级别锁),只有当该线程操作完成并提交事务之后,才会释放该锁,从而其他线程才能获取到该数据记录
- 分析比较:
- 1、乐观锁相对悲观锁效率更高,悲观锁的实现是给行记录加锁,在获取到锁的线程提交事务释放锁之前,其它线程需要等待,实现类似同步锁的效果
- 2、乐观锁在并发环境下只有一个线程获取到锁,其他线程都失败,这种方式虽然可以控制并发线程对共享资源的访问,但是牺牲了系统的吞吐量
- 3、由于乐观锁是使用version跟踪和控制共享资源,最终都要执行version+1和version匹配,所以在大量写环境下会影响数据库性能, 故“乐观锁”其实比较适合于“写少读多”的业务场景
- 4、悲观锁使用不当会造成死锁,当两个或两个以上线程同时持有对方请求的资源锁并尝试获取对方资源锁的时会产生死锁
2、 基于Redis的原子操作(redis是单线程的,同一时刻、同一部署节点中只有一个线程执行某种原子操作):
主要是通过Redis提供的原子操作SETNX与EXPIRE来实现。SETNX表示只有当Key在Redis不存在时才能设置成功,通常这个Key
需要设计为与共享的资源有联系,用于间接地当作“锁”,并采用EXPIRE操作释放获取的锁
SET KEY VALUE [EX seconds] [PX milliseconds] [NX|XX]
EX指的是Key的存活时间,而 NX表示只有当 Key不存在时才会设置其值,XX则表示当 Key存在时才会设置Key的值。
优缺点:
- 1、不可重入,当同一用户并发请求是,只有一个线程执行成功,其它的都会失败
- 2、SETNX原子操作需要设置失效时间,如果失效时间设置不当会影响系统性能
- 3、如果在设置SETNX之后,设置EXPIRE之前服务发生宕机,那么锁将不会释放
3、基于ZooKeeper的互斥排它锁(ZooKeeper是一款开源的分布式服务协调中间件,是由雅虎研究院相关的研发人员组织开发的):
- 这种机制主要是通过ZooKeeper在指定的标识字符串(通常这个标识字符串需要设计为跟共享资源有联系,即可以间接地当作“锁”)下维护一个临时有序的 节点列表Node List,并保证同一时刻并发线程访问共享资源时只能有一个最小序号的节点(即代表获取到锁的线程),该节点对应的线程即可执行访问共享资源的操作。
4、开源框架Redisson的分布式锁
- 一款高性能的分布式中间件,它架设在Reids基础上实现Java驻内存数据网格的综合中间件,底层基础架构采用基于NIO(即Non-Blocking IO,非阻塞式的输入输出)的Netty框架实现数据的传输
- 其内置了一系列的分布式对象、分布式集合、分布式锁及分布式服务等诸多功能特性,是一款基于Redis实现、拥有一系列分布式系统功能特性的工具包, 可以说是实现分布式系统架构中缓存中间件的最佳选择
- 它充分利用 Redis的Key-Value(键值对)数据结构及基于内存数据库所提供的一系列优势,使得原本作为协调单机多线程并发程序的工具包获得了协调分布式多机多线程并发系统的能力
关于分布式中间件使用可以查看我的其它博客,传送门:
RabbitMq讲解: https://blog.csdn.net/qq_41354978/article/details/112748735