最近觉得自己没有什么技术的提升,感觉有些着急,公司任务也不忙,决定先拜读大佬的《大型网站技术架构》一书,从中学习到新的想法思维。不知道能不能坚持到全书看完
第一章 大型网站架构演化
网站优化
- 应用服务和数据服务分离。根据需求的不同分配不同的服务器配置
- 遵循二八定律(80%的业务访问集中在20%的数据),将经常需要访问的数据进行缓存(缓存分为本地缓存和远程分布式缓存)
- 应用服务器集群解决并发问题
- 数据库读写分离
- CDN(使用户在访问数据的时候请求到离自己最近的服务器获取数据)和反向代理服务器(用户请求到中心机房后,如果反向代理服务器缓存着该请求的资源,则直接返回给用户)
- 使用NoSQL和搜索引擎(ES)
- 业务拆分,独立部署,分布式,消息队列
大型网站架构模式
- 网站分层架构
- 分割
将不同的业务进行分割,部署到不同的服务器,如有必要的话进行细分,比如购物业务将其细分为机票酒店业务、小商品业务、信息家电业务等
- 分布式
将业务需求细分后,模块独立部署
- 集群
每个独立的模块部署多台服务器达到一种集群的效果,提高并发性,提高可用性(当某一台服务器宕机时,不影响整体服务)
- 缓存
将一些热点内容,用户大流量访问的稳定内容放在缓存中,根据需求设置过期时间
- 异步
分布式消息队列,模块之间异步通信,典型的是生产者消费者模式,提高系统可用性(消费者服务器发生故障,不影响生产者服务器),加快网站响应速度(异步的原因,不需等待消费服务器的反馈),消除并发访问高峰
- 自动化
自动化测试,自动化代码管理,自动化部署等等
第二章 架构
前端优化
- 减少http请求,请求合并CSS,JS
- 使用浏览器缓存,采用该策略更新静态资源时,应该批量更新,有一定时间间隔的更新,以免用户浏览器突然大量缓存失效,造成服务器负载骤增
- 启用压缩
- 尽量减少Cookie传输
CDN加速
反向代理、服务器集群
用户访问静态资源时将它缓存在nginx中,其他用户再访问相同资源时,直接从NG上返回
缓存
缓存的本质是一张Hash表,存储KV
缓存不是一个可靠稳定的数据来源,如果新启的缓存没有任何数据,都需要后期的请求添加,那么会大大影响性能,所以在缓存启动的时候我们就可以将一些固定死的资源加载进缓存,比如地名、列表信息等,这种手法叫缓存预热
为了防止缓存穿透,所以当出现高并发的请求某个不存在的数据时,我们也对他进行缓存。值为null。
异步操作
使用消息队列将调用异步化
关于消息队列需要注意的是,因为是异步操作,对于生产者你没有办法第一时间知道是否业务操作成功,比如用户提交订单,可以返回订单正在提交字样,然后根据确切的成功与否进行二次提示或者邮件
代码优化
- 多线程
一台服务器最优启动线程数= [ 任务执行时间 / ( 任务执行时间 - IO等待时间 ) ] * CPU内核数
,最佳启动线程数和CPU内核数量成正比,和IO阻塞成反比。如果任务都是计算型任务,那么线程最多不超过内核数,如果都是等待磁盘的操作,那么启动多线程有助于提高任务并发量。
解决线程安全问题
- 使用局部对象,在方法内部创建对象,这些对象被每个进入该方法的线程进行重新创建
- 并发访问资源时,使用锁,通过锁的方式使多线程并发操作转化为进行顺序操作,但是对系统性能会产生严重影响
资源复用
对象池(连接池、线程池)的使用
数据结构
垃圾回收
理解垃圾回收机制,有助于程序优化和参数调优。
- 新创建的对象放在Eden区
- 当Eden区空间满时,触发Young GC,将Eden区还在使用的对象复制到From区,Eden区被清空
- 此时被清空的Eden区可以继续存放新创建的对象,直到Eden区再次空间满,再次触发Young GC
- 将Eden区和From区还在使用的对象复制到To区,Eden区和From区被清空
- Eden区再次空间满,将Eden区和To区还在使用的对象复制到From区,这样一直重复到某一个设定的阈值(调优点)
- 如果某些对象达到某一个阈值点后还没有被释放,则将该对象放入老年代
- 如果老年代空间也满了,那么触发FULL GC,该回收对系统性能会产生较大的影响
合理设计年轻代和老年代的大小,做到尽量少执行FULL GC
网站的高可用架构
集群Session管理
- Session复制 几台服务器集群同步共享Session,缺点是用户量很大的时候Session复制会占用大量的资源
- Session绑定 根据Nginx的规则,将同一IP的请求发放到同一台服务器
- 使用Cookie记录Session
- Session服务器 单独将Session抽离出来独立部署Session集群,可实现SSO登录
高可用服务
- 超时时间 每台服务器的调用超时时间需要设置,一旦超时,根据策略将请求提交到其他服务器上
- 异步调用 一些可以用异步调用的场景,比如说注册服务,一些不需要立即返回结果的请求
- 服务降级 一些服务降级将展示其他业务逻辑,还有关闭功能,比如关闭一些高峰时期不重要的功能,比如双11时期的用户评价等
- 幂等性设计 接口的幂等性
关于接口的幂等性,通常我需要注意的是增和改两个操作
- 代码逻辑层实现:状态的确立,比如在改操作是,添加限制条件,where status = ‘未支付’,只有在未支付的情况下才能进行支付
- 使用token机制实现接口幂等性:提交操作时附带token,redis进行删除该token(如果删除成功,说明操作执行成功,删除失败,则说明请求重复,如果进行select+del则会存在并发问题),并将新的token存入redis,返回给前端
高可用数据
- CAP原理(数据持久性、数据可访问性、数据一致性) 通常我们会放宽数据一致性这个要求,不要求强一致性,达到用户一致性或者最终一致性即可,用缓存辅助数据库,对于一些不经常更改的数据可以放入缓存