如何设计好一个接口?

前言

接口对于我们系统来说是必不可少的,可以称得上是系统的基石。一个好的接口我认为需要具备以下几方面:安全性、稳定性、高效性、可维护性、可读性。下面我们就根据这几个性质讨论一下设计一个好接口需要考虑哪些问题?

安全性

安全性对于接口来说重要性不言而喻。我们常见的Web漏洞包括:SQL注入、JSON反序列化漏洞、XSS攻击、CSRF 攻击、文件上传下载漏洞、DDoS 攻击、弱口令、证书有效性验证、内部接口在公网暴露、未鉴权等权限相关漏洞。

预防措施:

  • 数据验证:使用过滤器、拦截器进行输入数据验证;
  • 身份认证&会话管理:对重要操作的接口使用令牌保护;
  • 存储安全:使用加密算法:MD5、SHA256、3DES;
  • IP白名单、记录接口请求日志、敏感数据脱敏等等。

稳定性

接口稳定性包含两个方面一个是健壮另一个是可靠,这两个概念很容易弄混。

健壮性

健壮指的是接口对错误处理机制的能力。
体现在几个方面:接口限流、降级、接口响应超时处理、重试以及预警机制。

限流

限流,也称流量控制(Rate Limit)。是指系统在面临高并发,或者大流量请求的情况下,只允许指定的事件进入,超过的部分将被拒绝服务、排队或等待、降级等处理,从而保证接口的稳定性。

常见的限流算法:固定窗口限流算法(计数器)、滑动窗口限流算法、漏桶算法、令牌桶算法。

因为篇幅原因这里不在展开说明,有机会我们单开一章详细介绍一下。

接口响应超时处理

这种情况往往都是对接第三方接口时,因为网络等不稳定因素导致

这种情况我们可以采取:设置超时时间、接口重试机制、异步、预警等方案。

另外我们可以通过:System默认方式、StopWatch、AutoCloseable来统计接口的响应时间,以便对其进行监控处理。

可靠性

可靠性的设计可以主要考虑:幂等、事务一致性两方面。

幂等性

幂等指任意多次请求的执行结果和一次请求的执行结果所产生的影响相同。

说的直白一点就是查询操作无论查询多少次都不会影响数据本身,因此查询操作本身就是幂等的。但是新增操作,每执行一次数据库就会发生变化,所以它是非幂等的。

幂等问题的解决有很多思路,比如:

  • insert前先select
  • 加悲观锁:select … for update
  • 加乐观锁:表中增加一个timestamp或者version字段
  • 加唯一索引
  • 建防重表
  • 加分布式锁:redis、zookeeper

事务一致性

事务是一组不可分组的操作集合,这些操作要么都成功执行,要么都取消执行。

事务的四个特性(ACID):原子性、一致性、隔离性、持久性。

单体数据库不涉及网络交互,所以在多表之间实现事务是比较简单的(Spring事务轻松解决),这种事务我们称之为本地事务。

当单体数据库的性能达到瓶颈就需要进行分库分表以及服务化改造。

分布式事务就是指事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于不同的分布式系统的不同节点之上。

单体数据库事务很容易满足事务的 ACID 四个特性,提供强一致性保证,但是分布式事务要完全遵循 ACID 特性会比较困难。

为了追求分布式系统的高可用和高吞吐,分布式事务的解决方案一般提供的是最终一致性。

分布式事务

我们把提供最终一致性的事务称之为柔性事务,柔性事务一般遵循的是分布式领域中的 BASE 理论:

  • BA:Basic Availability,基本业务可用性。
  • S:Soft state,柔性状态。
  • E:Eventual consistency,最终一致性。

分布式事务有三种场景

  • 跨数据库分布式事务
  • 跨服务分布式事务
  • 混合式分布式事务

常见的分布式事务解决方案

  • XA 两阶段提交
  • TCC模式:支持 TCC 事务的开源框架有:ByteTCC、Himly、TCC-transaction。
  • Saga
  • 基于消息的分布式事务:基于事务消息的方案、基于本地消息的方案
  • 分布式事务中间件:Seata

高效性

我们可以使用多线程能够更加充分合理利用系统资源,使用缓存可以提高响应速度、

多线程的实现离不开两个类:Thread、Runnable。

同时我们也可以通过Future和Callable获取子线程的执行结果。

使用线程池可以管理并复用线程,减少频繁创建线程带来的上下文切换等问题。

谈到多线程就不得不聊聊线程安全问题。

线程安全问题

线程安全问题的两个场景:

  • 数据争用:两个数据同时去写,造成其中一方的数据要么被丢弃要么写入错误;
  • 竞争条件:执行顺序,比如去读取一个文件的内容,那么自然是在这个文件写完之后的,假设线程配合的不好,我在你没写完之前就来读取,这样就会造成顺序上的错误。

线程安全问题只在多线程环境下才出现,单线程串行执行不存在此问题。
保证高并发场景下的线程安全,可以从以下四个维度考量:

  • 数据单线程内可见,比如ThreadLocal;
  • 只读对象,final
  • 线程安全类:StringBuffer、ConcurrentHashMap
  • 同步与锁机制:synchronized、Lock等。

多线程的场景下还需注意死锁问题。

可维护性

可维护也可以称为可拓展。这就要在设计层面对接口进行良好的设计。
体现在对响应结果、异常处理、日志打印等要做统一的控制。
再有就是可以使用设计模式。

设计模式一共有23种,最常用比如:单例模式、代理模式、工厂模式、建造者模式、模板模式、策略模式等。

Spring源码中就使用了很多的设计模式,大家有兴趣可以了解一下。

可读性

可读性是为了给后人提供方便,正所谓铁打的营盘流水的兵。
我们在写接口的时候对复杂的逻辑不妨多加一些注释,这样不仅仅给方便其他人阅读,同样给自己带来遍历。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值