网站的问题主要是来自庞大的访问用户,高并发的访问量和海量数据。在这个科技时代,由于互联网的开放性,使得互联网网站更容易受到攻击,无论大型小型还是打酱油的网站,几乎都会受到黑客的侵害。
面对这些危机问题,许多人都会第一时间想到用服务器来预防,现在市面上的服务器的防御机制大多是集群防护,集群防护是指整个机房的防护,也是与其他人一起共享的这几个G的防护。比如说集群防护100G,其实真实的防护还不如10G的单机防御。只看数值不注重真实,往往会误入歧途,以为自己赚到了,其实是被坑了。
方案:
防御吧安盾立体式防御
它是可以解决所有网站可能会出现的一切安全问题。例如最常见的网站的高并发量,以及网站遭受到攻击等问题。防御吧安盾立体式防护可以帮助网站加速以及防御,隐藏源站服务器IP,有效解决网站并发量。
优势:
1、有立体式防护管理后台,可以自主设置缓存规则和缓存时间,可自主调整CC策略。
2、多节点分布加强网站的稳定性,网站稳定百度蜘蛛爬行抓取数据正常,网站排名自然就会提高。
3、隐藏网站服务器IP地址,确保网站服务器不受到任何影响。
4、防御DDOS、无视CC。
高并发的优化需要借鉴简书的一位作者
高并发优化
高并发除了需要对服务器进行垂直扩展和水平扩展之外,作为后端开发可以通过高并发优化,保证业务在高并发的时候能够稳定的运行,避免业务停滞带来的损失,给用户带来不好的体验
缓存:
服务端缓存
内存数据库
redis
memcache
方式
优先缓存
穿透 DB 问题
只读缓存
更新 / 失效删除
注意
内存数据库的分配的内存容量有限,合理规划使用,滥用最终会导致内存空间不足
缓存数据需要设置过期时间,无效 / 不使用的数据自动过期
压缩数据缓存数据,不使用字段不添加到缓存中
根据业务拆分布式部署缓存服务器
客户端缓存
方式
客户端请求数据接口,缓存数据和数据版本号,并且每次请求带上缓存的数据版本号
服务端根据上报的数据版本号与数据当前版本号对比
版本号一样不返回数据列表,版本号不一样返回最新数据和最新版本号
场景:
更新频率不高的数据
服务端缓存架构图
huancun_pt.png
场景
多级缓存
虽然Redis集群这种缓存的性能已经很高了,但是也避免不了网络消耗,在高并发系统中,这些消耗是可能会引起很严重后果的,也需要尽量减少。可以考虑多级缓存,将一些变更频率非常低的数据放入应用内缓存,这样就可以在应用内直接处理了,相比使用集中式缓存来说,在高并发场景还是能够提高很大效率的,可以参考【cache-redis-caffeine-spring-boot-starter】实现两级缓存,也可以参考开源中国的J2Cache,支持多种两级缓存的方式。需要注意的就是缓存失效时一级缓存的清理,因为一级缓存是在应用内,对于集群部署的系统,应用之间是没法直接通信的,只能借助其他工具来进行通知并清理一级缓存。如利用Redis的发布订阅功能来实现同一应用不同节点间的通信
CDN
CDN也是一种缓存,只是主要适用于一些静态资源,比如:css、js、png图片等,前端会使用的较多。在一些场景下,可以结合动静分离、前后端分离,将前端资源全部放入CDN中,能够很大程度提高访问效率。需要注意的是前端静态资源是可能会更新的,当有更新的时候需要刷新CDN缓存。或者另一种策略是在静态资源的地址上增加一个类似版本号的标志,这样每次修改后的路径就会不一样,上线后CDN就会直接回源到自己应用内获取最新的文件并缓存在CDN中。使用CDN就需要一套比较完善的自动化部署的工具了,不然每次修改后上线就会比较麻烦
前端缓存
前端html中可以配置静态资源在前端的缓存,配置后浏览器会缓存一些资源,当用户刷新页面时,只要不是强制刷新,就可以不用再通过网络请求获取静态资源,也能够一定程度提高页面的响应速度
缓存穿透
当使用缓存的时候,如果缓存中查询不到数据,就会回源到数据库中查询。但是如果某些数据在数据库中也没有,如果不做处理,那么每次请求都会回源到数据库查询数据。如果有人恶意利用这种不存在的数据大量请求系统,那么就会导致大量请求到数据库中执行查询操作。这种情况就叫做缓存穿透。在高并发场景下更需要防止这种情况的发生
防止:如果数据库中查询不到数据,可以往缓存里放一个指定的值,从缓存中取值时先判断一下,如果是这个指定的值就直接返回空,这样就可以都从缓存中获取数据了,从而避免缓存穿透的问题。也可以根据缓存对象的实际情况,采用两级缓存的方式,这样也可以减少缓存设备的请求量。redis是常用的缓存,但是不能存储null,因此spring cache模块中定义了一个NullValue对象,用来代表空值。spring boot中Redis方式实现spring cache是有一些缺陷的(spring boot 1.5.x版本)
缓存雪崩
缓存雪崩主要是指由于缓存原因,大量请求到达了数据库,导致数据库压力过大而崩溃。除了上面提到的缓存穿透的原因,还有可能是缓存过期的瞬间有大量的请求需要处理,从缓存中判断无数据,然后就直接查询数据库了。这也是在高并发场景下比较容易出现的问题
防止:当缓存过期时,回源到数据库查询的时候需要做下处理,如:加互斥锁。这样就能够避免在某个时间点有大量请求到达数据库了,当然也可以对方法级别做限流处理,比如:hystrix、RateLimiter。也可以通过封装实现缓存在过期前的某个时间点自动刷新缓存。spring cache的注解中有一个sync属性,主要是用来表示回源到数据查询时是否需要保持同步,由于spring cache只是定义标准,没有具体缓存实现,所以只是根据sync的值调用了不同的Cache接口的方法,所以需要在Cache接口的实现中注意这点
在缓存的使用方面,会有各种各样复杂的情况,建议可以整理一下各种场景并持续完善,这样可以在后续使用缓存的过程中作为参考,也可以避免因为考虑不周全引起的异常,对于员工的培养也是很有好处的。