文章内容
一、如何防止表单重复提交
- 前端。每次点击后都要等X秒才能点击。
- 数据库添加唯一索引
- 服务器返回表单页面时,会先生成一个subToken保存于session或redis,当表单提交时候携带token,如果token一致,则执行后续,并将服务器中的token删除。
二、如何设计一个秒杀系统
1、前端
在秒杀之前,按钮置灰,并且不给前端真正的请求地址。前端定时请求后端接口,如果到了秒杀时间,则返回给前端真正的地址,前端放开按钮,每次点击后都要等X秒才能点击。
2、服务器
服务器用nginx做集群、redis也做集群
3、限流
在秒杀之前,将秒杀数量的令牌存入到redis中,可以用list,每次来请求都去redis中取出令牌,如果获取到说明秒杀成功,然后去访问数据库下单,如果没有获取到,则说明商品卖完了。
4、消息中间件
如果秒杀数量比较多,例如上万十万,则秒杀成功之后,将成功的请求放入到mq或者kafka中间件中,再从消息队列中获取请求。
5、服务降级
为了以防万一,还是要做服务熔断降级。
三、分布式系统的接口幂等性设计
- 唯一id。每次操作,都根据操作和内容生成唯一的id,在执行之前先判断id是否存在,如果不存在则执行后续操作,并且保存到数据库或者redis等。
- 服务端提供发送token的接口,业务调用接口前先获取token,然后调用业务接口请求时,把token携带过去,务器判断token是否存在redis中,存在表示第一次请求,可以继续执行业务,执行业务完成后,最后需要把redis中的token删除
- 建去重表。将业务中有唯一标识的字段保存到去重表,如果表中存在,则表示已经处理过了
- 版本控制。增加版本号,当版本号符合时,才能更新数据
- 状态控制。例如订单有状态已支付 未支付 支付中 支付失败,当处于未支付的时候才允许修改为支付中等
四、管理分布式Session的四种方式
1、Session复制
应用服务器开启Web容器的的Session复制功能,在集群中的几台服务器之间同步Session对象。
方案简单,且从本机读取session也相当快捷,但有非常明显的缺陷:只能使用在集群规模比较小的情况下(企业应用系统,使用人数少,相对比较常见这种模式),当集群规模比较大的时候,集群服务器之间需要大量的通信进行Session的复制,占用服务器和网络的大量资源,系统负担较大。而且由于用户的session信息在每台服务器上都有备份,在大量用户访问下,可能会出现服务器内存都还不够session使用的情况。
2、Session会话保持
会话保持是利用负载均衡的原地址Hash算法实现,负载均衡服务器总是将来源于同一IP的请求分发到同一台服务器上。
这种方案虽然保证了每个用户都能准确的拿到自己的session,而且大量用户访问也不怕,但是这种会话保持不符合系统高可用的需求。这种方案有着致命的缺陷:一旦某台服务器发生宕机,则该服务器上的所有session信息就会不存在,用户请求就会切换到其他服务器,而其他服务器因为没有其对应的session信息导致无法完成相关业务。所以这种方法基本上不会被采纳。
3、Cookie记录
将session记录在客户端,每次请求服务器的时候将session放在请求中发送给服务器,服务器处理过请求后再将修改过的session返回给客户端。
利用cookie记录session是存在很多缺点:比如cookie的大小存在限制能记录的信息不能超过限制;比如每次请求都要传输cookie影响性能;比如cookie可被修改或者存在破解的可能,导致cookie不能存重要信息,安全系数不够。但是由于cookie简单易用,支持服务器的线性伸缩,而且大部分的session信息相对较小,所以其实很多网站或多或少的都会使用cookie来记录部分不重要的session信息。
4、Session集群
对于session服务器设计简单方式:
- 1.利用分布式缓存,数据库等,在这些产品的基础上进行包装,使其符合session的存储和访问要求。
- 2.另一种就是业务场景对session管理有很高的要求的时候需要开发专门的session服务管理平台。
五、如何保障请求执行顺序
- 一般来说,从业务逻辑上最好设计系统不需要这种顺序的保证,因为一旦引入顺序性保障,会导致系统复杂度的上升,效率会降低,对于热点数据会压力过大等问题。
- 首先使用一致性hash负载均衡策略,将同一个id的请求都分发到同一个机器上面去处理,比如订单可以根据订单id。如果处理的机器上面是多线程处理的,可以引入内存队列去处理,将相同id的请求通过hash到同一个队列当中,一个队列只对应一个处理线程。
- 最好能将多个操作合并成一个操作