但是不管怎么提升硬件性能,硬件性能的提升不可能永无止尽,所以最终还是要靠分布式解决
浏览器缓存是指当我们使用浏览器访问一些网站页面时,根据服务器端返回的缓存设置响应头,将响应内容缓存到浏览器,下次可以直接使用缓存内容或者仅需要去服务器端验证内容是否过期即可(js、css、html、png),这样可以减少浏览器和服务器之间来回传输的数据量,节省带宽,提升性能
比如淘宝:http://www.taobao.com/
第一次访问返回200,第二次刷新访问,返回响应码为304,表示页面内容没有修改过,浏览器缓存的内容还是最新的,不需要从服务器获取,直接读取浏览器缓存即可
我们也可以在Java 代码中通过设置响应头,告诉浏览器进行缓存
# web static
spring.web.resources.add-mappings=true
spring.web.resources.chain.cache=true
spring.web.resources.chain.enabled=true
# 静态资源在浏览器缓存3600s
spring.web.resources.cache.period=3600
spring.web.resources.static-locations=classpath:/static/
Nginx提供了expires 指令来实现缓存控制,比如:
location static {
root /opt/static/;
expires 1d;//全天
}
当用户访问时,Nginx拦截到请求后先从Nginx本地缓存查询数据,如果有并且没有过期,则直接返回缓存内容
CDN的全称是Content Delivery Network,即内容分发网络。CDN 是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。CDN的关键技术主要有内容存储和分发技术
CDN 它本身也是一个缓存,它把后端应用的数据缓存起来,用户要访问的时候,直接从CDN上获取,不需要走后端的 Nginx,以及具体应用服务器Tomcat,它的作用主要是加速数据的传输,也提高稳定性,如果从CDN上没有获取到数据,再走后端的Nginx 缓存,Nginx上也没有,则走后端的应用服务器,CDN主要缓存静态资源(js、css、html、png)
浏览器 -> CDN -> Nginx -> Redis -> DB
需要缓存的数据:经常需要读取的数据、热点数据(销量高的商品、热搜榜单、网红直播间)、IO瓶颈数据(文件、电影)、计算昂贵的数据、无需实时更新的数据(js/css/html/img),缓存的目的是减少对后端服务的访问,降低后端服务的压力
一个单体应用,当访问流量很大无法支撑,那么可以集群部署,也叫单体应用水平扩容,原来通过部署一台服务器提供服务,现在就多部署几台,那么服务的能力就会提升
部署了多台服务器,但是用户访问入口只能是一个,比如www.web.com,所以就需要负载均衡,负载均衡是应用集群扩容后的必须步集群部署后,用户的会话 session 状态要保持的话,就需要实现 session共享。
应用服务器集群、redis集群、MySQL集群(主从复制、读写分离)
单体应用,随着业务的发展,应用功能的增加,单体应用就逐步变得非常庞大,很多人维护这么一个系统,开发、测试、上线都会造成很大问题,比如代码冲突,代码重复,逻辑错综混乱,代码逻辑复杂度增加,响应新需求的速度降低,隐藏的风险增大,所以需要按照业务维度进行应用拆分,采用分布式开发
应用拆分之后,就将原来在同一进程里的调用变成了远程方法调用,此时就需要使用到一些远程调用技术: httpClient、hessian、dubbo、webservice等
随着业务复杂度增加,我们需要采用一些开源方案进行开发,提升开发和维护效率,比如 Dubbo、SpringCloud
通过应用拆分之后,扩容就变得容易,如果此时系统处理能力跟不上,只需要增加服务器即可(把拆分后的每一个服务再多做几个集群)
读写分离、分库分表(水平/垂直)
对于一些访问量大,更新频率较低的数据,可直接定时生成静态html页供前端访问,而不是访问jsp面
常用静态化的技术: freemaker、velocity
浏览器只需要请求静态页面,暂时不需要去访问数据库或者缓存来获取数据,浏览器直接加载html页即可,局部使用ajax发起请求更新。先给用户返回静态页面,后续再利用ajax请求数据(比如用户请求电商首页时,先返回纯html,其他的图片、视频资源使用ajax更新,请求地址都写为互联网绝对路径)
页面静态化可以提升网站稳定性,如果程序或数据库出了问题,静态页面依然可以正常访问
还可以延迟加载,根据滚动条的位置加载数据
采用比如Nginx实现动静分离,Nginx负责代理静态资源,Tomcat 负责处理动态资源
Nginx的效率极高,利用它处理静态资源,可以减轻后端服务器的压力,动静分离架构示意图:
Redis的并发量在7w,nginx的并发量在4w,tomcat的并发量在700左右,MySQL在600左右
队列的作用就是:异步处理、流量削峰、系统解耦
异步处理是使用队列的一个主要原因,比如注册成功了,发优惠券/送积分/送红包/发短信/发邮件等操作都可以异步处理
使用队列实现系统解耦,比如最主要的支付操作成功了,发消息通知物流,发票等操作都不用保证实时,无需同步调用这些接口,可以让这些消息入队,使用线程池慢慢处理
使用队列流量削峰,比如并发下单、秒杀等,可以考虑使用队列将请求暂时入队,通过队列的方式将流量削平,变成平缓请求进行处理,避免应用系统因瞬间的巨大压力而压垮。但需要保证入队的请求一定能完成
常见的消息队列产品:ActiveMQ/RabbitMQ/RocketMQ/kafka
通过复用对象,减少对象创建和垃圾收集器回收对象的资源开销,可以采用commons-pool2实现
实际项目采用对象池并不常见,主要在开发框架或组件的时候会采用
Druid、DBCP、C3P0、BoneCP
MySQL Server配置优化: mysqld启动时会加载my.cnf
,配置其中的相关配置可以优化server
如果某个二级索引不断被使用,二级索引成为热数据,那么InnoDB会根据在二级索引树上的索引值在构建一个哈希索引
来加速搜索(只适用于等值比较)。业务完成后,可以用show engine innodb status
查看哈希索引使用频率,若不高可以关闭
索引失效的情况
表数据量太大,导致查找慢:可以分库分表,或者将一些时间很久远的数据导出到专门的文件服务器中
log buffer和buffer pool太小,刷脏页频率过高
当只需要指定数量数据的时候,可以使用limit提前结束查找,无需扫描全表。limit m,n时最好先用主键id过滤掉前m个数据
参考:【MySQL】分析SQL的几种方式