专栏名称: Java极客技术
Java 人的社区,专注 Java 一百年!
目录
相关文章推荐
51好读  ›  专栏  ›  Java极客技术

「非广告」支付宝面试系统设计真题分享

Java极客技术  · 公众号  · 互联网安全 科技自媒体  · 2020-11-25 07:30

主要观点总结

本文分享了一道蚂蚁金服的面试题,关于设计程序以最短响应时间获取多种支付方式的可用性列表。文章涵盖了问题分析、设计要点以及相应的Java代码实现,包括多线程查询、缓存定时刷新等解决方案。

关键观点总结

关键观点1: 面试题目描述

用户有多种支付方式,需要通过实时调用远程服务获取可用性,设计程序以最短响应时间获取尽可能多的可用支付方式列表。

关键观点2: 解题分析

文章分析了题目的关键词,包括最短实时远程调用、高并发,并提出了多种解决方案,如遍历查询、引入缓存、定时刷新、多线程查询等。

关键观点3: Java代码实现

文章给出了多线程查询和缓存定时刷新的代码实现,并讨论了接口被高并发调用时的问题及解决方案。

关键观点4: 文章结尾

文章总结了分享的内容,并鼓励读者转发和加入知识星球。


正文

请到「今天看啥」查看全文


每天早上 七点三十 ,准时推送干货

Hello、早上好~

最近阿粉的朋友出去面试了一下蚂蚁金服,一面的时候收到一道系统设计题,今天跟大家分享一下。

ps:偷偷告诉你,这道题星球球友之前面试的时候也碰到了,这次相当于刚好押题了。

题目

用户有多种支付方式(余额、红包、优惠券,代金券等),假如每种支付方式需要通过实时调用远程服务获取可用性。在外部资源环境不变情况下,请设计程序以最短响应时间获得尽可能多的可用支付方式列表。

假定支付方式可用性咨询服务接口定义: PaymentRemoteSerivce 接口方法: ConsultResult isEnabled(String paymentType) ;

public class ConsultResult {

  public ConsultResult (boolean isEnable,String errorCode){
    this.isEnable = isEnable;
    this.errorCode= errorCode;
  }

  /** 咨询结果是否可用*/
  private boolean isEnable;
 
  /** 错误码 */
  private String errorCode;
 
  public boolean getIsEnable(){
    return isEnable;
  }
 
  public String getErrorCode(){
    return errorCode;
  }
 
}

题目要求:

「尽可能展示你的编码能力(Java语法、编码风格等),java语言肯定比伪代码得分高」

看到这里的小伙伴的可以思考一会哦

解题

这道题,说难真的不难。

拿到题目之后,我们首先分析一下,切记直接上手写。

在我们的分析过程,梳理设计要点,并且可以向面试官确认这些设计点是否正确,最后我们才开始真正写代码。

我们来看下这道题的关键词:

  • 最短
  • 实时
  • 远程调用
  • 另外需要考虑高并发

结合这几个关键点,第一个很容易想到的方案,遍历查询所有支付方式的可用性,然后返回。

「这种做法响应时间就是多次调用远程服务的总和。」

不过显然不符合设计要求。

第二种,我们可以想象一下,支付方式可用性在一段时间内不怎么会变化的,所以我们可以在第一种的方式基础上,优化一下,增加缓存保存之前的调用结果。

「这种方案只在前面查询的时候耗时较长,后面查询直接走缓存,速度较快。」

但是引入缓存有一个弊端,就是某一支付方式如果突然不可用了或者不可用支付突然变成可用了,那在缓存还未失效的这段时间,将会获取不准确的结果。

所以我们需要引入刷新进制,定时查询支付方式可用性,然后更新缓存。

当然如果在定时任务还未刷新的间隔,支付方式突然不可用,依然还是会存这个问题。

这个问题,第一种解决方案,加快定时任务刷新频率。

第二种方案,需要其他服务配合。如果某一支付方式突然从可用变成不可用,或者不可用变成可用了,这种情况发送相应的消息,这边服务受到消息及时更新缓存结果。

第二种设计方案,我们已经在一定程度上优化设计,不过还是存在一些问题。

主要问题还是在于第一次查询遍历查询所有支付方式的可用性,速度较慢。

那这个问题,我们其实就可以引入多线程查询,这样的话,响应时间最大值等于单一支付最长调用那一次。

结合以上的分析,我们代码可以如下:

多线程查询代码:

缓存定时刷新的代码如下:

考虑接口会被高并发调用,在缓存为空的时候,可能会有多个线程并发调用 asyncQueryALLPaymentTypes 查询所有的支付方式的结果。

但是实际上这里只需要一个线程查询即可,其他线程等待结果就可以。

所以接口使用双重查询锁(DCL)的方式,同时只会有一个线程去查询所有支付方式。

上述 DCL 的方式只是解决同一个应用内多线程的问题,但是多个应用间被并发调用,还是可能会多线程去查询所有支付可用性。

假设现有 10 个应用,缓存为空,极端情况下,10 个应用都使用多线程去查询支付方式可用性。

假设现有 5 个支付方式,短时间内发起 10 *5=50 次调用,这种调用量还是很少,完全可以接受。

好了,今天分享就到这里了~



< END >

如果大家喜欢我们的文章,欢迎大家转发,点击在看让更多的人看到。 也欢迎大家热爱技术和学习的朋友加入的我们的知识星球当中,我们共同成长,进步。




往期 精彩 回顾




年轻人不讲武德,竟然重构出这么优雅后台 API 接口
JVM 是如何加载 Java 类的?
重点丨什么是双重检查锁模式?以及为何需要 volatile 关键字?








请到「今天看啥」查看全文