抢票系统之高性能(CDN、缓存、读写分离)

本文探讨了构建高性能抢票系统的关键技术,包括CDN动静分离以减轻服务器压力,缓存策略如LRU、布隆过滤器防止穿透,以及缓存空数据和应对击穿、雪崩问题。此外,还介绍了读写分离以提高系统性能,通过主从库和中间件实现数据读写的高效处理。

抢票系统之高性能

1.高性能之CDN

1.1CDN动静分离

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jSFk74z5-1651541337066)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20220422090707845.png)]

静态特点的信息:商品的信息(不会变的数据可以放到本地的静态服务器上,防止过多的请求直接)

动态特点的信息:商品的库存

服务端也要有一份缓存,防止真的请求到后端,也是可以直接响应

特点

就是把大量的请求拦截在上游,让用户以更短的链路得到响应数据,这样的响应速度可以大幅度的提升,同时如果库存为0之后可以通过按钮置灰的方式把请求拦截在上游,不会再去访问服务器,同时类似于抢红包等业务场景要限制用户的提交频率

APP和WEB发起请求大部分静态数据可以从CDN中拿到静态的数据,动态数据和没有存储到CDN到静态数据可以从Cache和交易系统的数据库中拿到数据,前端页面除了按钮基本上都是静态页面

2.高性能之缓存

银行和金融用到缓存的很少因为要求的数据时效性很强

2.1 缓存处理流程

在这里插入图片描述

对于抢票系统来说车次就是适合存储到缓存当中的数据,整个流程就是用户发起查询车次的缓存,判断缓存中是否存在数据,若是存在数据则返回缓存中的数据,否则去服务端查看数据库中是否有响应的数据,如果有则返回数据的同时,更新缓存数据,否则返回空数据,结束。

但是缓存的空间是有限的如果不控制缓存中的数据的话,就有可能造成缓存OOM导致内存不可用

这里就涉及到如何把不常用的不用的缓存剔除掉,一般用到的缓存策略是LRU策略,最近最少使用,不使用最少使用的原因是当前不使用但是有可能下一秒使用的特别频繁容易误伤热点数据。

2.2 缓存关键技术实践

image-20220424153245839

设置了缓存的队列为2,超过就会被t除 ,也可以设置过期时间,如果缓存中没有找到数据就会执行CacheLoader的策略,将数据查出来后更新到缓存当中。

2.3 缓存穿透

防止不合理的请求去访问不存在的数据(eg:G1001车次本身在数据库中不存在,则不可能在缓存中找到,也不可能在数据库中找到,这样的数据就会一直访问数据库查询,返回空数据)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R92GWtXE-1651541337067)(/Users/zhaokaijie/Library/Application Support/typora-user-images/image-20220424163405574.png)]

2.3.1参数校验

image-20220424163813166

ID的长度命名规则等信息外面都是不知道的,可以利用ID做一些合理的校验揽截一些不合理的请求,还可以使用Token进行合法性校验。

2.3.2 布隆过滤器

image-20220424165748342

布隆过滤器的原理就是通过hash看是否在缓存上出现过,而不是缓存的具体数据是什么,这样的话就节省了大量的空间同时解决了缓存穿透的问题 ,具体的解决流程是只有能命中布隆过滤器的数据才是有数据的才去访问缓存或者数据库。尤其是拦截一些非法请求,怎么验证出现过是非常使用

适合的使用场景

不关注是什么数据,只关心是否存在

优点:存储量非常小、查询时间也是非常快的是快速命中的hash算法

具体实践

image-20220427110410510

2.3.3 缓存空数据

将第一次查到的空作为一条数据存储到缓存当中,使得下一次访问的时候可以在缓存中查询到空数据,防止一直访问数据库

2.4 缓存击穿

image-20220427135636933

当多个请求访问缓存的时候突然缓存失效了(过期了),大量的数据集中访问数据库,对数据库、服务器产生巨大的压力,导致数据库失效,甚至导致后端服务的不可用

2.4.1 枷锁

数据库压力过大的根源是,同一时间内太多的请求去拉取数据,导致压力过大,枷锁的原理是同时只让一个去访问数据库,之后更新缓存数据,其他的数据就可以直接访问缓存中的数据

image-20220428095025269

这里涉及到一个expireTime的问题,也就是说时间设置需要仔细点考虑,时间太短不能完成业务,时间太长的话占用了过多的系统资源

还有就是为什么这里要设置成productId和requestId这种k-v的形式

2.4.2 自动续期
image-20220428100331386

缓存是20分钟失效,只要起一个一步线程,定时任务在缓存到期前把这个缓存更新一下,这样就可以随时访问到缓存中的数据,避免了缓存击穿的问题,思路是在请求过来之前就把缓存更新,让请求直接去访问缓存中数据,这中方式叫做热加载(传统的方式为懒加载)

2.4.3 缓存用不失效

image-20220428100916863

相当于让缓存用不失效,这样的策略的使用场景很少,等于将缓存当作存储使用了,但是大多是情况下数据是在一直变化的需要动态更新

2.5 缓存雪崩

image-20220428101704751

缓存雪崩

1.有大量的热门缓存,同时失效,会有大量的请求直接去访问到数据库,会导致数据库在短时间承受不了巨大的压力而直接挂掉,

2.缓存的服务器的机房出现问题导致全部的缓存失效,请求直接访问数据库,会导致数据库在短时间承受不了巨大的压力而直接挂掉

雪崩的本质原因就是访问缓存的时候大量的缓存同步失效

后果十分严重,已经达到了不可控的程度

2.5.1 过期时间随机

实际的场景:车次的信息存储缓存设置的过期时间都是3分钟过期,这样经过预热后可能就同时失效

image-20220428104023770

通过增加一个随机数的方式把过期时间打散,这样即使出现缓存同时失效的情况也是小范围的情况

2.5.1 服务降级

image-20220428105042574

缓存出现问题大量不可用的状态下或者缓存直接挂掉的情况,正常情况下是需要去直接访问数据库,最好的结果是当缓存出现不可用的时候直接返回一个默认值,可以直接写到代码当中,也可以直接从配置中获取一个,设置一个全局开关当开关开启的状态下,直接返回一个默认值,这个开关可以通过 Apollo 动态的去推

3.高性能之读写分离

3.1代码封装

解决数据库的问题

存储的过程是一个IO类型,和内存计算存在一个天然的鸿沟,IO的速度很慢,所以对数据读写分离之后对业务的性能有很大的提升 ,

image-20220428135021384

数据库分为一个主库和一个从库,主库负责写业务,从库可以有多个,前提是这个流程对于时间要求不是很高,从主库复制信息到从库需要时间,这里我增加了一个车次的信息,从主库发送到从库可能需要3s时间,但是这个时间不会对用户的使用产生影响, 可以针对方法级别设置个性化的读写的配置,缺点是不能复用,工作量大,切换的时候需要全部重启。

总结就是要求数据同步性不是特别强的系统可以使用,

3.1.1 代码封装关键技术实现

image-20220501155929984

3.2中间件封装

image-20220501160048872

服务器根据标准SQl协议(JDBC协议)去访问数据库,不同的几点的数据库的负载,地位(主从)都可以在中间件层配置,这样对于服务来说就不感知数据库,只感知数据源的存在,这样运维就可以随意的配置数据库负载,随意的切换,上下节点,对数据库进行缩扩容都不受影响,中间件会将逻辑sql转化为各个节点上的物理sql,并且中间件可以识别数据库的主从,和每条sql执行的结果

3.2.1 数据层中间件封装关键技术实现
3.2.1.1database配置

image-20220502082528025

3.2.1.1datasource配置

image-20220502083358476

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值