第一章 分布式系统介绍 分布式系统的定义:组件分布在网络计算机上,组件间仅仅通过消息传递来通信并协调行动。 分布式系统的意义:
摩尔定律:当价格不变时,每隔 18 个月,集成电路上可容纳的晶体管数目会增加一倍,性能也将提升一倍。 线程与进程的执行模式 冯诺依曼结构:输入设备、输入设备、运算器、控制器、存储器。 基于共享容器协同的多线程模式:经典如生产者消费者问题,对于存储数据的容器或对象,有线程安全和不安全之分,对于不安全的容器或对象,一般可以通过加锁或者通过 Copy On Write 的方式控制并发。 通过事件协同的多线程模式:避免死锁 多进程模式:
网络通信基础知识 OSI 七层模型与 TCP/IP 模型: Socket 套接字进行网络通信开发时,用到的三种方式:BIO、NIO 和 AIO BIO:Blocking IO,采用阻塞的方式实现,一个线程处理一个 Socket,发生建立连接、读数据、写数据的操作时,都可能会阻塞。 NIO:Nonblocking IO,基于时间驱动思想,采用 Reactor 模式,可以在一个线程中处理多个 Socket 套接字 AIO:AsynchronousIO,异步 IO,采用 Proactor 模式,与 NIO 的差别是,AIO 在进行读写操作时,只需要调用响应的 read/write 方法,并且需要传入 CompletionHandler,在动作完成后会调用。 如何把应用从单机扩展到分布式
方式 1 和 2,透明代理:对发起方和处理方都是透明的
缺点:
方式 3,采用名称服务器直连的方式: 请求发起方和处理方直接没有代理服务器,而是直接连接。外部多了一个“名称服务”的角色,作用有:
名称服务只是起到一个地址交换的作用,在发起请求的机器上,需要根据从名称服务得到的地址进行负载均衡的工作。 优点如下:
缺点就是代码升级较复杂 方式 4,采用规则服务器控制路由的请求直连调用 与名称服务器不同的是,规则服务器并不和请求处理的机器交互,只负责把规则提供给请求发起的机器。 方式 5,Master+Worker 的方式 存在一个 Master 节点来管理任务,由 Master 把任务分配给不同的 Worker 进行处理。 运算器的变化 通过 DNS 服务器进行调度和控制 增加负载均衡设备,DNS 返回的永远是负载均衡地址 存储器的变化 同控制器的变化,加代理服务器、or 名称服务器、or 规则服务器 分布式系统的难点
第二章 大型网站及其架构演进过程 大型网站:访问量(PV)、数据量、业务复杂度 单机负载告警,数据库与应用分离 应用服务器负载告警,走向集群
Session 保存会话状态,在 Web 服务器上,各个会话独立存储,多台服务器不能保证每次请求都落在同一边的服务器上。解决方案如下: 1、Session Sticky:负载均衡根据会话标识进行转发,让同样的 Session 请求每次都发送到同一个服务器端处理 缺点:
2、Session Replication:会话在多态服务器上复制同步 缺点:
3、Session 数据集中存储 Session 数据不再 Web 服务器上,而是放在另一个集中存储的地方。 缺点:
4、Cookie Based:把 Session 数据放在 Cookie 中 缺点:
数据读压力变大,读写分离 1、采用数据库作为读库 缺点:
2、搜索引擎其实是一个读库 3、加速数据读取的利器——缓存
弥补关系型数据库的不足,引入分布式存储系统 分布式文件系统,解决小文件和大文件的存储问题 分布式 key-value 系统,提供高性能的半结构化支持 分布式数据库提供一个支持大数据、高并发的数据库系统 读写分离后,数据库又遇到瓶颈 尽管读写分离以及分布式存储系统,能够降低主库的压力,但是交易、商品、用户的数据都还在一个数据库中,压力还在继续增加,我们有数据垂直拆分和水平拆分两种选择; 1、专库专用,数据垂直拆分 垂直拆分即把不同的业务数据分到不同的数据库中。 问题:
2、单表达到瓶颈,数据水平拆分 水平拆分就是把同一个表的数据拆到两个数据库中。 问题:
数据库问题解决后,应用面对的新挑战 拆分应用
初识消息中间件 消息中间件是在分布式系统中完成消息发送和接收的基础软件。两个明显好处:异步、解耦。 第三章 构建 Java 中间件 三个领域的中间件:
构建 Java 中间件的基础知识 JVM 中堆分为三块:Young/Tenured/Perm,新生代 / 年老代 / 持久代 一般来说,新对象分配在新生代的 Eden 区,也可能直接分配在年老代,在进行新生代垃圾回收时,Eden 区存活的对象被复制到空的 Survivor 区,在下次新生代回收时,Eden 区存活的对象和这个 Survivor 存活的对象被复制到另外那个 Survivor 区,并且清空当前 Survivor 区,经过多次新生代垃圾回收,还存活的对象会被移动到年老代。 线程池
使用线程池的方式是复用线程的,不用每次都创建线程。而创建线程的开销占比较大。 synchronized synchronized 修饰静态方法、对象方法、代码块 ReetrantLock
volatile 可见性指一个线程修改变量值后,其他线程中能够看到这个值。volatile 虽然解决了可见性问题,但是不能控制并发 Atomics 原子操作,如 AtomicInteger 内部通过 JNI 的方式使用了硬件支持的 CAS 指令 wait、notify 和 notifyAll wait 是等待线程,notify 是唤醒一个等待线程(并不能指定,随机),notifyAll 是唤醒所有的等待线程。 CountDownLatch java.util.concurrent 包中的一个类,主要提供的机制是当多个线程都到达了预期状态或完成预期工作时触发事件,其他线程可以等待这个事件来触发自己后续的工作。 CyclicBarrier 循环屏障,可以协同多个线程,让多个线程在这个屏障前等待,知道所有线程都到达了这个屏障时,再一起继续执行后面的动作。 Semaphore Semaphore 是用于管理信号量的,构造时传入可供管理的信号量的数值。如果信号量只有一个,就退化到互斥锁了,如果多于一个,则主要用于控制并发数。 Exchanger 用于两个线程之间进行数据交换,线程会阻塞在 exchange 方法上,知道另外一个线程也到了同一个 Exchanger 的 exchange 方法时,二者进行交换。 Future 和 FutureTask Future 是一个接口,FutureTask 是一个具体实现类
getDataFromRemote2 还是使用率 getDataFromRemote 完成操作,并且用到了线程池:把任务加入线程池中,把 Future 对象返回出去。 并发容器 CopyOnWrite:更改容器时,把容器复制一份进行修改,用于读多写少 Concurrent:尽量保证读不加锁,并且修改时不影响读,所以比读写锁更高的并发性能 动态代理 继承 InvocationHandler 反射 Java 反射机制是指在运行状态,对于任意一个类,都能知道这个类所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。
网络通信的选择 BIO、NIO、AIO 第三方框架,MINA,Netty 第四章 服务框架 服务调用端的设计与实现 调用发起 ==> 寻址路由 ==> 协议适配和序列化 ==> 网络传输 ==> 反序列化 协议解析 ==> 得到结果返回给调用方 1、确定服务框架的使用方式 2、服务调用者与服务提供者之间通信方式的选择 3、引入基于接口、方法、参数的路由 4、多机房场景,避免跨机房调用,一是在服务注册中心甄别,二是地址过滤 5、服务调用端的流控处理 6、序列化与反序列化处理,Java 本身的序列化性能问题、跨语言问题、序列化后语言长度 7、网络通信实现选择:BIO、NIO、AIO 8、支持多种异步服务调用方式:Oneway,Callback,Future,可靠异步 服务提供端的设计与实现 1、如何暴露远程服务 2、服务端对请求处理的流程 3、执行不同服务的线程池隔离 4、服务提供端的流控处理 第五章 数据访问层 分布式事务
多机自增主键问题 考虑唯一性和连续性,UUID 生成方式(IP、MAC、时间等)连续性不好 实现方案 1:把 ID 集中放在一个地方进行管理,对每个 Id 序列独立管理,每台机器使用 Id 时都从这个 Id 生成器上取。 缺点:
实现方案 2:舍掉 Id 生成器,把相关的逻辑放到需要生成 Id 的应用本身。每个生成器读取可用的 Id,然后给应用使用,但是数据的 Id 并不是严格按照进入数据库顺序而增大的。 应对多机的数据查询 跨库 Join
外键约束 外键约束比较难解决,不能完全依赖数据库本身来完成之前的功能了。 跨库查询的问题及解决 一张逻辑表,对应多个数据库的多张数据表,在一些场景下比较复杂,如排序、最大最小求和等函数处理、求平均值、非排序分页、排序后分页。 如何对外提供数据访问层的功能 1、为用户提供专有 API 2、通用的方式,数据层 JDBC 3、基于 ORM 或类 ORM 接口的方式 直接基于 JDBC 驱动方式较好 ~ 数据层的整体流程 SQL 解析 ==> 规则处理 ==>SQL 改写 ==> 数据源选择 ==>SQL 执行 ==> 结果集返回合并处理 1、SQL 解析阶段
2、规则处理阶段
3、为什么要改写 SQL 分库分表后,同一个卖家的商品可能会分在多个库中,查询就要跨库。分布的不同数据库中的表的结构虽然一样,但是表的名字、索引名字未必一样,所以要修改 SQL。 还有需要修改 SQL 的地方,如跨库计算平均值,必须修改 SQL 获取数量、总数后再进行计算。 4、如何选择数据源,读写分析 5、执行 SQL 和结果处理阶段,异常处理和判断 第六章 消息中间件 JMS,Java Message Service 是 Java EE 中关于消息的规范,ActiveMQ 等是对这个规范的实现。如果是小型系统直接使用 JMS 是一个经济的选择,在大型系统中不适合使用 JMS。 如何解决消息发送一致性 消息发送一致性是指产生消息的业务动作与消息发送一致,即如果业务操作成功了,那么由这个操作产生的消息一定要发送出去。 1、发送消息给消息中间件 2、消息中间件入库消息 3、消息中间件返回结果 4、业务操作 5、发送业务操作结果给消息中间件 6、更改存储中消息状态 |
|