限制后端接口调用次数

11 篇文章 0 订阅

系列文章目录

第一章 AOP后端控制接口调用次数
第二章 前后端配合控制接口调用次数



背景

在限制后端接口调用次数的项目,由于自己是前端小白,加上评估工作量的时候,时间紧急,方案设计好,也和公司老同事将方案过了一遍,但是没有目前公司没有完善的技术方案评审流程,所以当时自己定的是使用AOP技术手段,在需要限制的接口上面加上注解,然后通过AOP来限制,代码实现后,AOP技术可以实现限制次数的功能,但是前端交互太差,特别是图片预览的接口,前端是将url直接绑定在img空间上面,后端接口报错,前端也是一点效果没有,所以没有办法,只能将整体的方案改成,后端提供统计接口,前端先调用统计接口。统计接口返回成功,才进行正常的业务。


一、整体方案

design

如图上图所示:在原有流程的基础上,新增请求统计接口的流程。统计接口收到请求后,先请求redis缓存的规则数据,再查询统计数据,判断是否超限,若超限,返回固定错误码;否则,更新统计次数。前端封装一个统一的组件,先触发统计接口,统计接口返回成功之后,再执行真正的业务。

二、注意点

1.规则编辑

由于规则数据目前存储在db和redis,所以编辑规则的时候,需要考虑数据db和redis数据的一致性,采用延迟双删。
edit

2.批量插入数据

2.1 insert ignore into

insert ignore into

insert ignore into会根据主键或者唯一索引进行判断,若数据库中没有该数据,就插入新的数据,和普通的insert into 一样。若数据库中有该数据,就忽略这条插入语句,不执行该插入操作。
但是这个目前的业务场景,明显不符合,所以也放弃该方案。

2.2 replace into

replace into

replace into会根据根据主键或者唯一索引进行判断。若数据库中存在该数据,则先删除该数据,然后插入新的数据,相当于先执行delete,再执行insert 。若不存在该数据,则直接插入新的数据,和普通的insert into一样。这个和目前的业务场景也不一样,放弃该方案。

2.3 insert into … on duplicate key update

insert into ... on duplicate key update

insert into 语句末尾指定的 on duplicate key update,会根据主键或者唯一索引进行判断。若数据库有该条数据,则直接更新原生数据,相当于update。若数据库没有该条数据,跟普通的insert into 一样。
当前的业务场景和这个比较匹配,开始先选用的这个方案,大概的sql类似如下:

insert into `t_data`(`rule_id`, `object_type`, `object_id`, `object_source`, `start_time`, `end_time`, `num`, `operate_type`, `create_time`, `update_time`) values 
(7, 1, 'b', 'c', STR_TO_DATE('2022-01-06 00:00:00','%Y-%m-%d %H:%i:%s'), STR_TO_DATE('2022-01-06 23:59:59','%Y-%m-%d %H:%i:%s'), 1, 1, now(), now()) ,
(7, 1, 'b', 'c', STR_TO_DATE('2022-01-06 00:00:00','%Y-%m-%d %H:%i:%s'), STR_TO_DATE('2022-01-06 23:59:59','%Y-%m-%d %H:%i:%s'), 2, 1, now(), now()) ,
(7, 1, 'b', 'c', STR_TO_DATE('2022-01-06 00:00:00','%Y-%m-%d %H:%i:%s'), STR_TO_DATE('2022-01-06 23:59:59','%Y-%m-%d %H:%i:%s'), 3, 1, now(), now()) ,
(7, 1, 'b', 'c', STR_TO_DATE('2022-01-06 00:00:00','%Y-%m-%d %H:%i:%s'), STR_TO_DATE('2022-01-06 23:59:59','%Y-%m-%d %H:%i:%s'), 4, 1, now(), now()) ,
(7, 1, 'b', 'c', STR_TO_DATE('2022-01-06 00:00:00','%Y-%m-%d %H:%i:%s'), STR_TO_DATE('2022-01-06 23:59:59','%Y-%m-%d %H:%i:%s'), 5, 1, now(), now()) ,
(7, 1, 'b', 'c', STR_TO_DATE('2022-01-06 00:00:00','%Y-%m-%d %H:%i:%s'), STR_TO_DATE('2022-01-06 23:59:59','%Y-%m-%d %H:%i:%s'), 6, 1, now(), now()) ,
(7, 1, 'b', 'c', STR_TO_DATE('2022-01-06 00:00:00','%Y-%m-%d %H:%i:%s'), STR_TO_DATE('2022-01-06 23:59:59','%Y-%m-%d %H:%i:%s'), 7, 1, now(), now()) ,
(7, 1, 'b', 'c', STR_TO_DATE('2022-01-06 00:00:00','%Y-%m-%d %H:%i:%s'), STR_TO_DATE('2022-01-06 23:59:59','%Y-%m-%d %H:%i:%s'), 8, 1, now(), now()) ,
(7, 1, 'b', 'c', STR_TO_DATE('2022-01-06 00:00:00','%Y-%m-%d %H:%i:%s'), STR_TO_DATE('2022-01-06 23:59:59','%Y-%m-%d %H:%i:%s'), 9, 1, now(), now()) 

on duplicate key update num = num + values(num);

但是在自测的过程中,jmeter测试经常出现死锁的情况,原因就是该语句插入时容易造成死锁,具体可以参考:面试官:MySQL 唯一索引为什么会导致死锁,此外,由于加了唯一索引,接口的请求速度太慢。考虑到当前的业务场景,一个是实际的业务场景没有多少并发的场景,但是接口的调用影响客户的交互,此外不需要对统计数据如此精确,所以最终直接使用insert into,另外在查询统计数据是,只获取id最小的一条数据。此外还有两个优化接口速度的地方见下面***3接口速度调优***

3.接口速度调优

3.1 批量更新

将原来代码中的多次update合并成一条update语句,提高效率。

3.1.1 foreach

此方法需要sql连接allowMultiQueries=true

<update id="updateBatch" parameterType="com.xxx.xxx">
        <foreach collection="list" item="item" index="index" separator=";">
            update xxx set 
            <if test="item.name != null">
                name = #{item.name,jdbcType=VARCHAR}
            </if>
           
            where id = #{item.id,jdbcType=BIGINT}
        </foreach>
    </update>
3.1.2 CASE WHEN

选用此方案

<update id="updateBatch" parameterType="com.xxx.xxx">
       update xxx set 
       <trim prefix="set" suffixOverrides=",">
          <trim prefix="num = case" suffix="end,">
          	  <foreach collection="list" item="item" index="index">
          	  	 <if test="item.num != null">
          	  	    when id = #{item.id, jdbcType=BIGINT} then #{item.num,jdbcType=INTEGER}
          	  	 </if>
          	  </foreach>
          </trim>
       </trim>
	   where id in (
	   <foreach collection="list" item="item" index="index" separator=",">
	       #{item.id, jdbcType=BIGINT}
	   </foreach>
	   )
</update>

3.2 优化查询条件

由于配置的规则时间维度可以按日、按月、按年来统计,所以统计数据的时候,需要记录统计的开始时间,统计的结束时间。然后在查询统计数据的时候,根据开始时间 <= 当前时间 <= 结束时间 来过滤,但是由于这样的范围查询容易产生间隙锁,所以将当前时间,换成统计的开始时间,统计的结束时间,来查询,避免范围查询造成的间隙锁。

3.3 拆分统计类型

当前业务诉求,有不同的操作类型,刚刚开始的时候,将不同的类型的统计次数放在不同的字段,查询统计的数据时,查询某个操作类型,会锁定其他的操作类型,所以新增操作类型字段,将不同操作类型拆分为不同记录,拆分锁的粒度。

总结

(1)需求评审的时候,需要提前多看看,多想几个What,How,进行并进行详细方案设计,特别是涉及自己不了解的领域,例如本次的前端内容,能够考虑到方案的方方面面,开发的时候直接根据方案开发即可。
(2)方案需要进行评审,最好把涉及的各方拉倒一起,一起过一下,明确下来。
(3)自己的主职工作是后端开发,虽然不给自己设置限制,但是还是要以后端为主,前端的开发,一方面自己也没有精力投入学习,另外这块也不是自己的主要点,完全是不讨好的工作。能够拒绝前端的开发工作,就尽量拒绝。
(4)要有自己的想法,有自己的原则,学会拒绝别人,不要做好好先生。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值