书籍介绍:https://book.douban.com/subject/25867042/
为什么要分布式?
升级单机的处理能力的性价比越来越低,单机的处理能力存在瓶颈
分布式系统更加稳定和可用(单机挂了就挂了,分布式挂了一般还有备用/不至于整个链路全挂)
大型网站架构演进过程
在我们最开始接触Java项目的时候,一般来说是单机的(数据库、Web服务器都是同一台机器)
- 网站对外开放以后,访问量增大,服务器的压力也随之提高
此时,我们最简单的做法就是可以将数据库和应用分开,这样可以缓解一下当前系统的压力
应用服务器的压力继续增大,我们可以把应用服务器做成集群(加机器)
加了台应用服务器以后,就出现新的问题了:
用户请求的时候,走哪台服务器?
Session
是依赖单台服务器的,那Session怎么处理?
负载均衡
解决用户走哪台服务器,我们就在用户请求到达应用服务器之前
- 加了一个负载均衡器(用户请求会到哪台应用服务器的逻辑)
- 比如说,一个用户请求过来,负载均衡器指派这个请求到服务器A
- 另一个用户请求过来,负载均衡器指派这个请求到服务器B
- 这样就平摊了请求:这种方式就叫做轮询
Session的问题,一般来说我们可以将
Session
保存在Redis上就行了
读写分离
随着业务的发展,我们的数据量和访问量都在增长
- 现在有不少的业务都是读多写少的,对于这种业务也是会直接反应到数据库上
于是,我们可以增加一个读库,写入的操作走服务器的写MySQL,读取的操作走服务器的读MySQL
- 这样就实现了读写分离
一般来说,我们的写库也叫做主库,读库也叫做从库,在互联网架构中,这叫做主从架构,比如常见的架构:一主多从
针对读多写少的业务,我们还有优化策略,引入搜索引擎和缓存
- 搜索引擎也相当于一个读库,使用搜索引擎的倒排表方式,能够大大提升检索的速度
- 缓存则将热数据放入内存中,如果查询的数据在缓存中存在,则直接返回
分库分表
读写分离之后,数据库还是遇到了瓶颈,此时我们就可以采用分库分表策略了:
- 垂直拆分:
- 不同的业务数据分到不同的数据库
- 水平拆分:
- 将同一张表的数据拆分到不同的数据库中(原因是这张表的数据量/更新量太大了)
分布式存储系统
在数据存储方面,除了关系型数据库之外,如果有别的业务场景,可能还需要引入分布式存储系统
- 分布式文件系统
- 分布式Key-Value系统
- 分布式数据库
数据库问题解决之后,应用也面临着挑战(应用的功能会越做越多,应用也随之越做越大)
- 为了不让应用持续变大,这就需要把应用拆开,从一个应用变为两个/多个应用
远程的服务调用
不同功能/模块之间的调用不再单纯通过本机调用,引入了远程的服务调用
某个应用只有一台机器上运行着,如果这台机器上出现了问题,导致这个应用无法运行,这就叫单点故障
系统很多的情况下,我们在写远程调用代码的时候就可能要考虑到以下的问题:
我们肯定是不希望每次远程调用的时候都贴上重复的Socket代码,要是调用远程方法像调用本地方法一样简单就好了
某个服务应用为了实现高可用,集群了(多台机器部署同一套应用),那远程调用的时候选择哪一台机器进行调用?
网络之间的传输协议用现成的HTTP呢?还是自定义一套通信协议呢?
因为我们想调用远程方法像调用本地方法一样
- 那么在网络上就需要传输Java对象,要传输Java对象,就必须得对其进行序列化和反序列化的处理
- 能实现序列化的操作也有很多,选择哪一种方式呢?
选择哪种网络之间的通讯模式(Bio、Nio、以及Aio模式)?
由于系统之间的调用会非常多,我们自然是不希望写重复的代码的,所以服务框架(也可以说是RPC框架)就应运而生了
- 有了服务框架,我们就可以实现多个系统之间以统一的方式来进行远程调用了
服务框架
一个服务框架需要考虑的问题其实远不止上面那些,比如说:
- 服务框架与Web应用和Web容器的关系是什么?
- 服务框架和应用是绑定在一起吗?
- 服务框架作为Web应用的一个依赖包,还是说服务框架只是Web应用的一个扩展(没有和Web应用打包绑定在一起)
- 服务框架的jar包和Web应用的jar包冲突了怎么办?
- 为了保证系统的稳定性,流量控制也应该要考虑到
- 在远程调用的时候,需不需要以更细粒度的方式来进行选择