微服务相关问题

消息幂等性(防重复提交 或者 消息队列重复消费问题)

接口幂等性就是用户对同一操作发起了一次或多次请求的对数据的影响是一致不变的,不会因为多次的请求而产生副作用

重复消费: 消息队列一般都能保证消息至少一次投递。通常消息被成功消费后,消费者都会发送一个成功标志给MQ,MQ 收到这个标志就表示消息已经成功消费了,就不会再发送给其他消费者了。 但如果因为网络这个标志没有送到 MQ 就丢失了,MQ 就认为这个消息没有被成功消费,就会再次发送给其他消费者消费,就造成了重复了。

1.前端防重复提交
1.1 按钮只能点击一次

用户点击按钮后将按钮置灰,或者显示 loading 状态

1.2 RPG模式

即 Post-Redirect-Get,当客户提交表单后,去执行一个客户端的重定向,转到提交成功页面。避免用户按 F5 刷新导致的重复提交,也能消除按浏览器后退键导致的重复提交问题。目前绝大多数公司都是这样做的,比如淘宝,京东等

2.后端保证幂等性的方法
2.1 防重表(效率低)

增加一个防重表,业务唯一的id作为唯一索引,如订单号,当想针对订单做一系列操作时,可以向防重表中插入一条记录,插入成功,执行后续操作,插入失败,则不执行后续操作

2.2 token 机制实现

在这里插入图片描述
客户端会先发送一个请求去获取 token,服务端会生成全局唯一的 ID 作为 token 保存在 redis 中,把这个 ID 返回给客户端,客户端第二次调用业务请求的时候携带这个 token,服务端会校验这个 token,如果校验成功,则执行业务,并删除 redis 中的 token,如果校验失败,说明 redis 中已经没有对应的 token,则表示重复操作,直接返回指定的结果给客户端

2.3 状态机

对于很多业务是有一个业务流转状态的,每个状态都有前置状态和后置状态,以及最后的结束状态。如订单的待提交,待支付,已支付,取消。已支付的状态的前置状态只能是待支付,而取消状态的前置状态只能是待支付,通过这种状态机的流转我们就可以控制请求的幂等。假设当前状态是已支付,这时候如果支付接口又接收到了支付请求,则会抛异常或拒绝此次处理。

public enum OrderStatusEnum {

    UN_SUBMIT(0, 0, "待提交"),
    UN_PADING(0, 1, "待支付"),
    PAYED(1, 2, "已支付待发货"),
    DELIVERING(2, 3, "已发货"),
    COMPLETE(3, 4, "已完成"),
    CANCEL(0, 5, "已取消"),
    ;

    //前置状态
    private int preStatus;

    //状态值
    private int status;

    //状态描述
    private String desc;

    OrderStatusEnum(int preStatus, int status, String desc) {
        this.preStatus = preStatus;
        this.status = status;
        this.desc = desc;
    }

    //...
}

一致性问题

1、强一致性

如果你的项目对缓存的要求是强一致性的,那么请不要使用缓存。这种一致性级别是最符合用户直觉的,它要求系统写入什么,读出来的也会是什么,用户体验好,但实现起来往往对系统的性能影响大。

2、弱一致性

这种一致性级别约束了系统在写入成功后,不承诺立即可以读到写入的值,也不承诺多久之后数据能够达到一致,但会尽可能地保证到某个时间级别(比如秒级别)后,数据能够达到一致状态。

3、最终一致性

最终一致性是弱一致性的一个特例,系统会保证在一定时间内,能够达到一个数据一致的状态。这里之所以将最终一致性单独提出来,是因为它是弱一致性中非常推崇的一种一致性模型,也是业界在大型分布式系统的数据一致性上比较推崇的模型。一般情况下,高可用只确保最终一致性,不确保强一致性。

强一致性,读请求和写请求会串行化,串到一个内存队列里去,这样会大大增加系统的处理效率,吞吐量也会大大降低。

数据库和缓存(redis )一致性问题

结论:如果真的要求一致性很强的情况下就不应该使用缓存!
推荐:先更新数据库,再删除缓存,如果删除失败用消息队列重试来删缓存
在这里插入图片描述
1、想要提高应用的性能,可以引入「缓存」来解决

2、要考虑缓存和数据库一致性问题,方案有两种:

  • 更新缓存 「更新数据库 + 更新缓存」
  • 删除缓存 「更新数据库 + 删除缓存」

3、采用「更新数据库 + 更新缓存」方案,又要考虑是先更数据库还是先更新缓存,因为要考虑到更新前者成功后再去更新后者出现网络波动或更新失败的问题,这两者表现出的结果也不一样,且在「并发」场景下无法保证缓存和数据一致性,解决方案是加「分布锁」,但这种方案存在「缓存资源浪费」和「机器性能浪费」的情况

4、采用「 更新数据库 + 删除缓存」方案,也要考虑先后顺序,推荐采用「先更新数据库,再删除缓存」方案,为保证两步都成功执行,需配合「消息队列」或「订阅变更日志」的方案来做,本质是通过「重试」的方式保证数据最终一致。

延时双删策略:是针对先删缓存在更新数据库的解决方案

(1)先淘汰缓存;
(2)再写数据库;
(3)休眠1秒,再次淘汰缓存;

这么做,可以将1秒内所造成的缓存脏数据,再次删除!数据库有主从即「读写分离 + 主从库延迟」也会导致缓存和数据库不一致,缓解此问题的方案也是「延迟双删」,凭借经验发送「延迟消息」到队列中,延迟删除缓存,同时也要控制主从库延迟,尽可能降低不一致发生的概率

缓存更新策略

参考 Redis缓存使用技巧和设计方案
缓存中的数据会和数据源中的真实数据有一段时间窗口的不一致,需要利用某些策略进行更新,下面会介绍几种主要的缓存更新策略。

redis 内存淘汰策略使用到了(lru 和 lfu)

FIFO(队列,公平)、LRU(时间最久没用)、LFU(使用频率最低)

1、LRU/LFU/FIFO算法剔除

参考 https://www.cnblogs.com/hongdada/p/10406902.html
参考 https://blog.csdn.net/qq_34158555/article/details/101528258
FIFO算法: (First In First Out)先进先出,维护一个队列,该算法会将那些经常被访问的页面也被换出,从而使缺页率升高。

LRU算法:(The Least Recently Used),最近最久未使用算法,一种常见的缓存算法,在 Redis, Memcached 中广泛使用。如果一个数据在最近一段时间没有被访问到,那么可以认为在将来它被访问的可能性也很小。故空间满时,最久没有访问的数据最先被置换淘汰。
实现思想
1:用用数组+时间戳的方式
2:当一个页面被访问时,将这个页面移到链表表头。这样能保证链表尾是最近最久未访问的。

LFU算法:(Least Frequently Used ),最近最少使用算法,也是常见的缓存算法,如果一个数据在最近一段时间很少被访问到,那么可以认为在将来它被访问的可能性也很小。故空间满时,最小频率访问的数据最先被淘汰。

剔除算法通常用于缓存使用量超过了预设的最大值时候,如何对现有的数据进行剔除。如 Redis 使用maxmemory-policy 这个配置作为内存最大值后对于数据的剔除策略。

2、超时剔除

对数据一致性较低,给缓存数据设置过期时间,让其在过期时间后自动删除,expire 命令。缓存数据超时后,请求会落到数据库,再把新数据重新添加到缓存

3、主动更新

应用方对于数据的一致性要求高,需要在真实数据更新后,立即更新缓存数据。例如可以利用消息系统或者其他方式通知缓存更新。

在这里插入图片描述
①低一致性业务建议配置最大内存和淘汰策略的方式使用。
②高一致性业务可以结合使用超时剔除和主动更新,这样即使主动更新出了问题,也能保证数据过期时间后删除脏数据。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
微服务相关的技术包括但不限于以下几个方面: 1. 服务拆分与架构设计:将单一的应用程序拆分成多个独立的服务,每个服务负责一个特定的业务功能,通过定义清晰的接口进行通信。 2. 服务注册与发现:通过服务注册中心来管理和维护各个微服务的地址和元数据信息,使得微服务能够自动注册和发现其他服务。 3. 负载均衡:通过负载均衡算法,将请求均匀地分发到多个实例上,提高系统的性能和可伸缩性。 4. 断路器:通过断路器模式,实现服务的容错处理,当某个服务出现故障或响应时间过长时,可以快速失败或返回预设的默认值,避免级联故障。 5. API 网关:作为微服务架构的入口,对外提供统一的 API 接口,处理请求路由、安全认证、请求限流、日志记录等功能。 6. 分布式事务:处理多个微服务之间的事务一致性问题,确保数据的完整性和准确性。 7. 服务监控与日志:通过监控和日志记录来实时追踪和分析微服务的运行状态,包括服务调用次数、响应时间、错误率等指标。 8. 容器化与编排:使用容器技术如Docker来打包和隔离微服务,通过容器编排工具如Kubernetes来管理和部署多个容器化的微服务。 9. 高可用与容灾:通过部署多个实例、使用负载均衡、数据备份等机制来实现系统的高可用性和容灾能力。 10. 自动化部署与持续集成/持续交付:采用自动化工具和流程,实现微服务的快速部署、自动化测试和持续集成/持续交付,提高开发效率和产品发布速度。 以上列举的是微服务架构中常见的技术,根据具体的需求和场景,可能还会涉及其他技术和工具。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值