微服务——服务依赖与治理-服务调用异常、超时,id生成

1.在高并发场景下,由于超时或者异常导致服务之间的RPC调用失败,及时的对服务进行补偿(滞后性)、兜底、降级或者熔断,可以有效避免整个调用链路不可用,保障业务的正确执行!

比如 降级补偿:请求获取token时在userCenter中因为一系列问题(网络,服务器等)出现获取不到,我们可以从redis中获取token

2.高并发下自动降级和手动降

    自动降级是指当服务达到某个阈值的时候,自动进行屏蔽某些服务的调用:超时策略,设置一个阀值

    手工降级通常需要人工进行设置,往往不是非常的即时,但也是必不可少的:手动设置一个阀值

3.动态开关

    动态开关和动态降级差不多的理念,通常在于高并发下采取的开启与关闭某些抗压的功能组件。(流量高时候走mq)

4.灰度发布

      灰度这个概念非常的重要,一般来说互联网公司发布一个重要的功能,或者新需求上线,首先都需要进行灰度(分批发布保证项目正常使用)

代码中指定城市走新的功能,等稳定后将该判断取消走新方法逻辑

5.主流ID生成策略

    最简单的就是利用java.util.UUID工具类进行生成,ID没有排序策略,这种方式的问题就是比如我要查询一批数据,进行入库时间做数据排序的时候,

    只能够自己在表里设置一个create_time ,给这个字段添加索引然后进行排序。(比如雪花算法、数据库自增主键、sequence等)

顺序ID生成方式:

    TimeBaseGenerator生成id:具有时间先后顺序

    使用带有生成顺序的ID生成策略,KeyUtil里生成的ID是有时间先后顺序的,我们可以使用ID天然进行排序,这做法比较好的就是没必要浪费一个索引字段了。

从数据库的角度来讲,一般能尽量减少索引,就减少索引。因为索引虽然可以提升查询性能,但也是需要占用空间的,并且一张表的最好索引不要超过3个,

所以在做索引优化的时候,往往也是要根据业务进行考量。

业务ID生成方式:

    使用带有业务含义的ID生成策略,这种方式也在传统应用系统、特定的场景下非常的好用。比如我们现在有一张商品货架表,这张表的数据维度是这样的,

比如是按照城市和区域来划分的。 比如北京我们按照100000为基本维度数据,100010为北京的一个区域,100020则为另一个区域,以此类推,200000可能

是另一个城市,200010 则为另一个城市的区域。那么我们在生成货架信息ID的时候,可以按照前六位为城市和区域的方式进行组织,后面可以拼接一个简单

的32位UUID字符串

从前六位来看,这四条数据其中前三条数据属于一个城市下的数据信息,那么我们查询一个城市下的货架数据,查询语句可以为: select * from goods_shelf gs where id > '10001000000000000000000000000000000000'          and id <   '20000000000000000000000000000000000000'

如果想要查询1000(北京)这个城市下10区域的数据,则查询语句如下: select * from goods_shelf gs where id > '10001000000000000000000000000000000000'          and id <   '10002000000000000000000000000000000000'    

注意:我们即避免了新的索引建立,只是单纯的利用业务ID的方式,就可以查询出某一个维度的数据,注意我们后面的32位随机UUID需要使用”0”进行补位.

6.统一ID生成方式

    建立一个统一的ID生成服务器,我们的服务去调用统一ID生成服务器去进行获取ID,这种方式,需要考虑两个最基本的问题,第一,是如何解决ID生成在并发下的重复生成问题,第二,是如何承载高并发ID生成的性能瓶颈问题

    建立一个统一的ID生成服务器,我们的服务去调用统一ID生成服务器去进行获取ID,这种方式,需要考虑两个最基本的问题,第一,是如何解决ID生成在并发下的重复生成问题,第二,是如何承载高并发ID生成的性能瓶颈问题

zookeeper的分布式锁:只能解决10次左右配置变更,解决不了高并发下的一系列问题,

redis的分布式锁:单个redis能解决上千高并发问题,但是分布式redis也不能解决分布式高并发问题

    1 最简单的就是利用zookeeper去进行分布式锁,但是zookeeper的写性能在QPS上千的并发下肯定是扛不住的,这也是第二个问题,如何承载该并发下的性能瓶颈。 2 所以我们又想到了Redis缓存,利用Redis的分布式锁去解决此类问题.首先第一点,Redis本身也会有性能问题,再超高的并发下可能会有延迟等一些细节问题,第二点我们的服务调用链过长,我们的服务调用可能失败,因为期间过程是调用统一ID生成服务,然后再去Redis里set id,可能会出现重复情况,那么就需要进行重试,这期间可能会发生服务调用超时问题,导致我们的服务调用失败。

redis下面高并发统一id生成会发生重试等

7.统一ID生成方式

    业界比较主流的分布式ID生成器的策略是提前加载,也就是预加载的机制,我们可以预先生成一批唯一的ID,然后直接放到内存里,由服务的调用方直接获取就好,获取之后就直接进行删除,当ID使用过半的时候或者达到临界值的时候再进行生成一批ID。这有点类似于高性能的一些框架中的内存预加载,或者一些内存计算、流式计算中spark里的预加载机制。看来在软件设计的领域,所有的思想都是相通的。 当然,如果统一ID生成服务的ID生成策略想要加入具体的业务规则,我们可以预先进行一些配置,比如订单服务、物流服务、支付ID等等,在获取ID的时候可以加一些生成的业务规则,这些都是可以在统一生成服务的后台进行配置的。

    使用单点唯一的ID生成策略,也就是我们固定的一个机器节点来生成一个唯一的ID,这种方式的好处是可以做到全局唯一,主要还是通过拼接的方式去实现的。 比如我们每一个真实的线上服务节点都要有一个唯一的机器码,然后采用组合的方式进行生成:机器码 + 时间戳 + 自增序列 + 其他业务规则。当然也可以使用其他的组合方式,只不过大家需要注意的一点就是服务器时间的NTP问题,也就是服务器时间的同步问题.

    NTP是网络时间协议(Network Time Protocol),它是用来同步网络中各个计算机的时间的协议. 在高并发的场景下,我们的生成ID请求量非常的巨大,就会暴露出NTP的问题。 举个例子,如果单纯的采用: 机器码 + 时间戳  或者 机器码 + UUID 这种组合,在高并发下可能会有订单重复的问题。

    机器码: ABK007 当前时间戳:1528018092517 ID生成为: ABK0071528018092517               NTP就是你的服务器系统的时间会定时去获取,然后进行更新校准,也就是说,我们现在的系统时间是:1528018092517

    生成了一个ID为ABK0071528018092517的订单,紧接着我们的服务器进行了NTP的时间校准,这个时候系统时间肯定是向前走的,比如我们在校准前的一刻,系统时间为:1528018092530 ,恰巧我们的服务器时间走的比较快,然后经过了一次NTP服务时间校准,我们的系统时间可能就会回到从前,回到过去.. 回到我们生成订单的时间之前,比如为1528018092513,那么高并发下在后续的订单id生成的时候可能还会生成一个订单为: ABK0071528018092517 ,这个时候我们就会产生订单id重复问题。

    所以,我们要解决高并发下的NTP问题就要考虑周全: 比如使用:机器码 + 时间戳 + 自增序列,即时是我们的时间戳被NTP服务校准产生回调,那么我们自增系列永远会在单点下保证自增,比如AtomicLong就是很好的一种原子自增序列计数器

8.分布式统一ID生成策略-统一ID生成服务的架构设计思路

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

择业

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值