官方邮箱:enquiry@xcourse.sg
微信分享群:@新加坡工作内部分享群
WhatsApp群:@Singapore Jobs & Internships
Telegram中文群:@新加坡工作内部分享群
Telegram英文群:@Singapore Jobs
------------------------------------------------------------------------------------------------------
幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。
前端重复提交选中的数据,后台只产生对应这个数据的一个反应结果。
当客户端请求页面时,服务器会生成一个随机数token,并且将token放置到session当中,然后将token发给客户端(一般通过构造hidden表单)。下次客户端提交请求时,token会随着表单一起提交到服务器端。服务器端第一次验证相同过后,会将session中的token值更新下,若用户重复提交,第二次的验证判断将失败,因为用户提交的表单中的token没变,但服务器端session中token已经改变了。
update table_xxx set name=#name#,version=version+1 where version=#version#;通过条件限制 update table_xxx set avai_amount=avai_amount-#subAmount# where avai_amount-#subAmount# >= 0要求:quality-#subQuality# >= ,这个情景适合不用版本号,只更新是做数据安全校验,适合库存模型,扣份额和回滚份额,性能更高;
利用数据库表单的特性来实现幂等,常用的一个思路是在表上构建唯一性索引。需求是博客点赞问题,要想防止一个人重复点赞,可以设计一张表,将博客id与用户id绑定建立唯一索引,每当用户点赞时就往表中写入一条数据,这样重复点赞的数据就无法写入。
1、首先为表添加一个版本字段version
2、在执行更新操作前呢,会先去数据库查询这个version
3、然后执行更新语句,以version作为条件,例如:
UPDATE T_REPS SET COUNT = COUNT -1,VERSION = VERSION + 1 WHERE VERSION = 1
4、如果执行更新时有其他人先更新了这张表的数据,那么这个条件就不生效了,也就不会执行操作了,通过这种乐观锁的机制来保障幂等性。
当消费者消费完消息时,在给生产端返回ack时由于网络中断,导致生产端未收到确认信息,该条消息会重新发送并被消费者消费,但实际上该消费者已成功消费了该条消息,这就是重复消费问题。
消费端实现幂等性,就意味着,我们的消息永远不会消费多次,即使我们收到了多条一样的消息
业界主流的幂等性操作:
整个思路就是首先我们需要根据消息生成一个全局唯一的ID,然后还需要加上一个指纹码。这个指纹码它并不一定是系统去生成的,而是一些外部的规则或者内部的业务规则去拼接,它的目的就是为了保障这次操作是绝对唯一的。
将ID + 指纹码拼接好的值作为数据库主键,就可以进行去重了。即在消费消息前呢,先去数据库查询这条消息的指纹码标识是否存在,没有就执行insert操作,如果有就代表已经被消费了,就不需要管了。
对于高并发下的数据库性能瓶颈,可以跟进ID进行分库分表策略,采用一些路由算法去进行分压分流。应该保证ID通过这种算法,消息即使投递多次都落到同一个数据库分片上,这样就由单台数据库幂等变成多库的幂等。
我们都知道redis是单线程的,并且性能也非常好,提供了很多原子性的命令。比如可以使用 setnx 命令。
在接收到消息后将消息ID作为key执行 setnx 命令,如果执行成功就表示没有处理过这条消息,可以进行消费了,执行失败表示消息已经被消费了。
使用 redis 的原子性去实现主要需要考虑两个点
关于不落库,定时同步的策略,目前主流方案有两种,第一种为双缓存模式,异步写入到缓存中,也可以异步写到数据库,但是最终会有一个回调函数检查,这样能保障最终一致性,不能保证100%的实时性。第二种是定时同步,比如databus同步。
答:首先宕机问题要尽量避免,通过一些高可用的方案降低宕机的风险,如果确实宕机了,对于已发送但未被消费的消息,可以自己去做补偿或者投递到延迟队列里处理,宕机会造成生产端消息堆积,如果对消息实时处理要求比较高,需要提前预备一些应急方案另起服务去处理这些消息。
redis实现幂等很简单,我以redis实现接口的幂等性为例说明。你可以自定义一个幂等注解,然后配合AOP进行方法拦截,对拦截的请求信息(包括方法名+参数名+参数值)根据固定的规则去生成一个key,然后调用redis的setnx方法,如果返回ok,则正常调用方法,否则就是重复调用了。这样可以保证重复请求接口在一定时间内只会被成功处理一次。至于锁的有效时长要根据业务情况而定的。
1、生产者已把消息发送到mq,在mq给生产者返回ack的时候网络中断,故生产者未收到确定信息,生产者认为消息未发送成功,但实际情况是,mq已成功接收到了消息,在网络重连后,生产者会重新发送刚才的消息,造成mq接收了重复的消息
2、消费者在消费mq中的消息时,mq已把消息发送给消费者,消费者在给mq返回ack时网络中断,故mq未收到确认信息,该条消息会重新发给其他的消费者,或者在网络重连后再次发送给该消费者,但实际上该消费者已成功消费了该条消息,造成消费者消费了重复的消息;
1、mq接收生产者传来的消息:
mq内部会为每条消息生成一个全局唯一、与业务无关的消息id,当mq接收到消息时,会先根据该id判断消息是否重复发送,mq再决定是否接收该消息。
2、消费者消费mq中的消息:
也可利用mq的该id来判断,或者可按自己的规则生成一个全局唯一id,每次消费消息时用该id先判断该消息是否已消费过
Topics: 面经