什么是分布式系统
1,一定是由多个节点组成的系统。 2,每个节点不是孤立的,而是相互联通的。
分布式系统的意义
- 升级单机处理能力的性价比越来越低
- 单机处理能力存在瓶颈
- 出于稳定性和可用性的考虑
线程与进程的执行模式
- 互不相通的多线程模式 多个线程之间独立进行,互不通信
- 基于共享容器协同的多线程模式 比较常见的场景就是生产者消费者模式,这个队列就是多个线程会共享的一个容器或者数据对象。对于这种多线程环境下对同一份数据的访问,我们需要有所保护和控制,确保访问的正确性。
- 通过事件协同的多线程模式 例如某个线程执行到某个步骤时,需要等待另一个线程执行完某步骤,才能继续执行。实际情况往往很复杂,我们需要避免死锁的发生。
网络IO实现方式
- BIO方式 即Blocking IO,采用阻塞的方式实现。也就是一个Socket套接字需要使用一个线程来进行处理。建立连接、读数据、写数据时都有可能会阻塞。如果在支持并发的连接时,就需要更多的线程来完成这个工作。
- NIO方式 Nonblocking IO,基于事件驱动的思想。明显的好处是不需要为每个Socket套接字分配一个线程,而可以在一个线程中处理多个Socket套接字相关的工作。
- AIO Asynchronous IO,异步IO。AIO在进行读写操作时,只需要调用相应的read/write方法,并需要传入CompletionHandler(动作完成的处理器);在动作完成后,会调用CompletionHandler。
分布式系统的难点
- 缺乏全局时钟
- 面对故障独立性 分布式系统由多个节点组成,整个分布式系统的一部分有问题,而其他部分正常运行,我们称之为故障的独立性。
- 处理单点故障 如果某个功能只有单个及其在支撑,切发生了故障,我们称之为单点故障,我们可以把单点变为集群来避免单点故障,或者: 给单点做好备份,出现故障时自动恢复,降低恢复需要的时间 降低单点故障的影响范围。
大型网站的演化历程
(略)和《大型网站技术架构 核心原理与案例分析》这本书讲的比较类似。
java并发编程的类、接口和方法
这些都是属于java并发编程的知识,之后会精读一本相关的书籍。
- 线程池 系统频繁创建和销毁线程需要很大开销,所以需要线程池来执行相应任务。
- synchronized 可以保证在同一时刻,只有一个线程可以执行某个方法或者代码块,同时可以保证一个线程的变化可见(可见性)。
- ReentrantLock 可重入锁,ReentrantLock提供了tryLock 方法。调用该放啊放的时候,如果当前线程池有锁,返回结果为true。否则为false。
- volatile 轻量级的实现变量可见性的方法,只能修饰变量。
- Atomics 属于java.util.concurrent.atomic包,用以提供一些原子操作。
- wait notify notifyAll 属于java的 Object对象上的三个方法。用来完成线程间的状态通知。
- CountDownLatch 属于juc包中的一个类,当多个线程都达到了预期状态或者完成预期工作后触发事件,其他线程可以等待这个事件来触发自己后续的操作。
- CylicBarrier 循环屏障 ,当多个线程都到达了这个屏障时,再一起继续执行后面的操作。
- Semaphore
- Exchanger 用于在两个线程之间交换数据。线程会阻塞在Exchanger的exchange方法上,直到另一个线程也到了同一个Exchanger的exchange方法时,二者进行交换,然后这两个线程继续执行自身相关的代码。
- Future和FutureTask // todo 后面在并发编程中再详细学习 Future是一个接口,FutureTask是一个具体实现类。
数据库从单机到分布式的挑战和应对
-
水平拆分和垂直拆分的困难 垂直拆分就是把一个数据库中不同的业务单元的数据分到不同的数据库中。 垂直拆分会带来以下影响 1,单机的ACID保证被打破了。数据到了多机以后,原来的单机事务会收到很大影响。 2,一些Join操作会非常困难,因为数据存在不同的数据库里 3,靠外键去约束的场景会受影响
水平拆分就是把相同的业务单元的数据拆分到多个数据库中。水平拆分同样会有以下影响: 1,同样会有ACID被打破的情况 2,同样有Join操作被影响的情况 3,靠外键去进行约束的场景会有影响 4,依赖单库的自增序列生成唯一ID会受影响 5,针对单个意义上的表的查询要跨库
-
单机变为多机以后,事务如何处理 如果能避免分布式的事物,还是避免为好;如果一定要引入分布式的事物,那么可以考虑最终一致性,不必追求强一致性。
-
多机的Sequence问题与处理 当转变为水平分库以后,原来单库中的Sequence及自增Id的做法需要改变。可以采用以下两种方式之一: 1,全局的id生成器 2,每个应用单独生成id,彼此之间可以进行通信。
-
应对多机的数据查询 1,跨库的Join 如果需要Join的数据分布在多个数据库中,想要完成跨库的Join是比较麻烦的,解决的思路有以下几个:在应用层面把原来的Join操作分为多次数据库操作;数据冗余,把原来需要Join的操作变为单表查询;借助外部系统(例如搜索引擎)解决一些跨库的问题。 2,外间约束 外键约束的问题比较难解决,不能完全依赖数据库本身来完成之前的功能。入股要对分库后的单库做外键约束,就要求分库后每个单库的数据是内聚的,否则只能靠应用层的判断、容错方式了。
-
跨库查询的问题及解决 分库分表以后,可以对查询结果在应用上进行合并,这相对比较简单,但是一些复杂场景下需要进行较为复杂的操作。 排序:在应用层对查询结果进行多路的归并排序;如果查询出来的数据未排序,就要进行一个全排序。 函数处理 求平均值:改为查询sum和count,然后对多个数据来源的sum求和,count求和以后,计算平均值。 非排序分页:对于多个表,可以采取等比例或者等步长的取数据。 排序后分页:如果想取出整体的第n页,每个表都取出n页的数据,然后进行归并排序。排序后再根据排序取出结果。
消息中间件
本书讲的内容不是特别详尽,之后会学习专门讲消息中间件的书籍。