使用分布式锁时,分布式锁加在事务外面还是里面,有什么区别?

典型回答 在使用分布式锁与事务注解(如 Spring 的 @Transactional)一起时,分布式锁的位置(锁在事务外还是事务内)对于程序的行为和事务的一致性具有重要的影响。 其实这个问题本质就是锁的粒度和事务的粒度之间的关系,到底谁应该更大一些? 锁的粒度大于事务粒度 即在加锁之后,再调用一个带事务注解的方法,伪代码如下: 1 2 3 4 5 6 7 8 9 lock.lock(); try { @Transactional public void method() { // 事务性操作 } } finally { lock.unlock(); } 这个方式的优点是事务的时长不受锁的影响。一般来说我们的分布式锁都是通过Redis等实现的,这就涉及到一个远程调用,那么就会导致拖长事务的问题。 ✅为啥不要在事务中做外部调用? 缺点就是锁的时间会更长,跨越了整个事务。因为锁的时间更长了,那么整个系统的吞吐量也就会更低了。 事务的粒度大于锁粒度 即在开启事务之后,再进行加锁,伪代码如下: 1 2 3 4 5 6 7 8 9 @Transactional public void method() { lock.lock(); try { // 事务性操作 } finally { lock.unlock(); } } 这个方式的优点是锁的时长比较短,并发度会更高一些。 ...

March 22, 2026 · 1 min · santu

加分布式锁之后影响并发了怎么办?

典型回答 很多面试官咋问关于分布式锁的问题之后,会追加一句:你这个地方用了分布式锁,那不是影响了并发度了么。这么做真的合适吗? 很多人容易被问蒙了,不知道该如何回答。确实加了分布式锁是会影响并发度的。那么他就不是一个好的方案了吗? 其实,这里是大家忽略了对于并发的理解。 我们说,加分布式锁的目的是什么?防止发生并发?这里的并发是什么并发?其实是对于共享资源的争抢并发,比如重复下单,消息重投等等的。这种情况下我们才会加分布式锁来防止出现错误。 那么这里加锁防止的并发是什么?是同一个用户的同一个行为的重复操作! 那我们通常说的系统的并发,如抗的QPS,这个并发指的是什么?是一个提供同一时段能响应的请求数,这里的请求包含同一个用户的,也包含不同用户的。 虽然我们加锁把一个用户的重复请求给拦住了。但是,正是因为我们拦住了,使得系统不需要去浪费资源处理这些重复请求,那么就可以有更多资源响应其他用户的正常请求了。 所以说,我们虽然通过加锁的方式防止了一些并发,但是我们拦截的都是我们不希望他们发生的,或者说是异常并发。但是系统的整体并发并没啥影响,反而因为我们拦了一些异常请求后,它能处理更多的正常请求,并发反而上来了。

March 22, 2026 · 1 min · santu

数据库乐观锁和悲观锁以及redis分布式锁的区别和使用场景?

典型回答 锁机制是用来管理多个请求对同一数据进行操作时可能出现的冲突和数据一致性问题。主要分为乐观锁和悲观锁两种类型。 悲观锁 悲观锁假设最坏的情况,即在数据处理过程中,总是假设会发生冲突,因此在数据处理之前先加锁。这种锁通常由数据库自身提供支持,如MySQL的SELECT FOR UPDATE。 他的主要使用场景是: 当数据竞争较多,冲突频繁发生时。 更新和删除操作多的应用场景。 乐观锁 **乐观锁采用一种宽松的加锁机制,它假设多个事务在大多数时间不会同时修改同一数据。通常是通过版本号或时间戳来实现。**每次数据更新过程中,检查版本号或时间戳是否发生变化,如果没有变化,则进行更新;如果已经变化,则放弃更新或重试。 他的主要使用场景是: 当数据竞争较少,冲突不频繁时,乐观锁能减少锁的开销,提高系统的整体性能。 适用于读多写少的应用场景。 乐观锁和悲观锁区别 乐观锁适用于读操作频繁,写操作相对较少的场景。悲观锁适用于写操作较为频繁,且并发写入的概率较高的场景。 乐观锁和悲观锁还有个区别:乐观锁因为比较乐观,所以一般是先做业务逻辑操作,比如参数处理,内存中进行模型组装调整,然后再去更新数据库。悲观锁因为比较悲观,所以会先尝试加锁,然后再去做业务逻辑操作。 也就是说,乐观锁是先干活,后加锁。悲观锁是先加锁,再干活。 而高并发的写操作时,你干了一大堆活,把模型都组装好了,内存计算也都做完了,结果最后去数据库那更新的时候发现版本号变了。这不是大冤种吗? 所以,应该是先尝试获取锁,如果获取锁成功,再进行业务操作,否则就直接返回失败。这样可以做fail-fast。 综上,在高并发场景中,一般来说**并发写入的冲突较为频繁,所以建议优先考虑悲观锁。**即在做并发操作前,先尝试获取锁,如果获取锁成功,在进行业务操作,否则就直接返回失败。 Redis分布式锁 分布式锁是为了控制分布式系统中多个进程间的执行顺序,用于保护跨多个系统的共享资源。其实,我们前面提到的数据库的Select For Update,也是分布式锁的实现方式的一种。而因为Redis有更好的性能,所以更适合用来做分布式锁。 分布式锁的主要使用场景: 在多个应用或服务需要共同访问同一资源时使用,如在微服务架构中保护共享资源。 适用于处理跨多个节点的业务流程,保证数据的一致性和系统的稳定性。 也就是说,用数据库悲观锁的地方,都可以用Redis分布式锁。当然Redis也支持乐观锁。但是一般用的比较少而已。 ✅如何用Redis实现乐观锁? 什么时候用数据库的悲观锁,什么时候用Redis的分布式锁呢? 1、如果是单体应用,在做数据库操作的时候,建议直接基于数据库的悲观锁来做并发控制。如果是分布式应用,二者都可以。 2、如果不想额外引入Redis,也可以直接基于数据库做悲观锁控制。 除了以上两种情况以外,在做并发控制的时候,建议用Redis的分布式锁,而不是数据库的悲观锁(分布式锁)。主要有几个原因: 1、Redis更快,性能更好,可以有更快的响应。 2、Redis实现的分布式锁功能更多,比如可重入,续期等等,这些都是数据库的悲观锁不支持的。 3、数据库悲观锁可能会锁表,影响整体性能。 4、数据库的链接资源要比Redis更加珍贵,建议把这些非业务逻辑操作放到Redis中去抗,而不是用数据库抗。

March 22, 2026 · 1 min · santu

为什么不用分布式锁来实现秒杀?

典型回答 ✅让你设计一个秒杀系统,你会考虑哪些问题? ✅库存扣减如何避免超卖和少卖? 上面两篇文章中,介绍过秒杀的设计,其中关于库存扣减这里,我们选择用 lua 脚本实现的高效的库存扣减,于是有人提出了疑问:为啥不用Redis 的分布式锁,而要用 lua 脚本? 为啥不用不用分布式锁?其实答案就是没必要! 我们要实现秒杀的库存扣减,最重要的是两个点:1、抗更高的并发。**2、避免超卖**** 。**尤其重要的就是这个防止超卖,这也是我们加锁的目的。 拿我们常用的 Redisson 分布式锁来说,如果用了 tryLock,不考虑 waitTime的合理性情况下,和 lua 脚本的执行也差不多,就是排队执行。 但是,如果我们用 lua 脚本,可以直接用利用他的原子性特性,在一个脚本中实现库存的检查、扣减等动作。这样才能避免超卖! 如果使用分布式锁,在不使用 lua 脚本的情况下,每次库存扣减操作都需要多次与 Redis 服务器通信(例如,加锁、读取库存、扣减库存、释放锁等)。这不仅增加了网络延时,还增加了系统的复杂性。 而如果使用 Lua 脚本,所有操作可以在一次脚本执行中完成,这大大减少了网络传输时间和通信次数。 那有人说,我先加分布式锁,然后再用 lua 脚本不行吗?这。。。不就是脱裤子放屁吗?直接用 lua 脚本不就好了吗,因为利用 Redis 的单线程机制,Lua 脚本的执行本身就是串行化的。 ✅为什么Lua脚本可以保证原子性? 而且, Lua 脚本是在 Redis 服务器内部执行,它直接操作内存中的数据,执行效率是非常高的。而且使用 Lua 脚本实现的话,我们可以将库存扣减的逻辑集中处理,不需要在应用层做额外的同步处理。这样可以使得应用层的代码更加简洁,易于维护。 而且,用分布式锁需要细致的管理,包括锁的设置、维护锁的存活时间、处理死锁问题等。如果锁没有正确管理,可能会导致死锁或者锁失效,进而影响系统的稳定性和数据一致性。 扩展知识 lua和事务的区别 ✅Redis的事务和Lua之间有哪些区别?

March 22, 2026 · 1 min · santu

为什么不直接用原生的BlockinQueue做消息队列

典型回答 直接使用原生的 BlockingQueue 来做消息队列在某些场景下是可以的,但是非常不建议,因为它存在以下几个问题: 1. 缺乏分布式特性 BlockingQueue 是一个本地队列,无法在多个节点之间共享数据。可能会存在单机瓶颈以及流量倾斜,比如某台机器的任务比较多,但是其他的机器却没有啥任务要执行。 而Kafka、RabbitMQ、ActiveMQ 等支持分布式的消息队列,它们可以在多个节点之间共享数据,支持水平扩展。多个消费者可以一起来消费这些消息。 2. 无持久化支持 BlockingQueue 中的数据存储在内存中,一旦应用系统崩溃或重启,队列中的数据将会丢失。 而消息中间件都是带有持久化功能的,这些系统可以将消息存储在磁盘上,确保在系统故障时数据不会丢失。 3. 无高级特性支持 BlockingQueue 不支持消息确认、重试、死信队列、延迟消息、事务消息等高级消息队列功能。 而专业的MQ都提供了这些功能。 4. 缺乏管理和监控工具 BlockingQueue 没有内置的管理和监控工具,无法方便地监控队列的状态、消息的积压情况等。 而像Kafka、RocketMQ等,他们都带有管理和监控工具,提供了完整的管理和监控界面,可以方便地管理和监控消息队列。比如一些消息的轨迹查看,消费情况查看,重新发送等等。 5. 性能和吞吐量限制 BlockingQueue 适用于单机环境,处理大量消息时性能可能不足,无法满足高吞吐量的需求。 而高性能的分布式消息队列(如 Kafka),这些系统专门为高吞吐量设计,能够处理海量消息。

March 22, 2026 · 1 min · santu

Spring Event和MQ有什么区别?各自适用场景是什么?

典型回答 我们都知道,Spring是提供了Event机制的,可以在发送一个事件,然后再基于这个事件做监听处理,这个流程好像和MQ有点像。都是典型的生产者-消费者的模式。 有很多事情,我们用这两者都能实现,主要是因为他们有很多共同点: 生产者消费者模式,这个就不用说了,通过这种方式可以实现解耦,即生产者只负责发送事件,消费者负责监听处理,二者之间的耦合相比于直接调用是比较弱的,中间的联系只是一个事件的定义而已。 一对多的模式,无论是Spring的事件还是MQ,都支持一发多收,一个发送者发送消息,其他的多个消费者一起监听这个消息做自己的业务逻辑。 异步处理,MQ是异步的这个没啥好说的了,大家都很容易理解。Spring Event默认是同步的,但是他也支持异步,能基于线程池实现一个异步的事件消费。 但是,他们之间还有很多不同: 事件/消息的持久化,MQ的事件是可以在磁盘上进行持久化存储的。但是Spring的事件机制的话,是没有持久化的,它是基于JVM内存的,一旦应用重启或者崩溃,未处理完的事件也会随时消失 削峰填谷,MQ天然提供了削峰填谷的能力,因为MQ自己会通过队列做存储,这个队列可以起到一个很好的缓冲作用。而Spring Event的事件没有一个缓冲。 失败重试,基于MQ,可以做失败重试,MQ自己会针对失败的消息进行重新投递,但是Spring的Event失败了没办法重试,需要自己进行异常的处理。 特殊功能,MQ针对消息提供了很多特殊的功能,比如延迟消息、顺序消息、事务消息等等,而Spring Event就是玩出花来,也就是自定义个线程池进行处理。。。 但是Spring Event相比MQ也有好处,那就是简单,非常简单。 所以,在实际的业务中,如果是在自己的业务中需要做一些解耦或者一发多收的操作,比如订单创建后,异步创建一条订单流水。这种就可以基于Spring Event来做,并且利用线程池来进行异步并提升执行效率。 但是,需要考虑失败的问题,一旦处理失败了,需要有补偿机制,比如通过定时任务进行补偿处理。 而在多个系统之间交互的时候,就不能用Spring Event了,因为他没办法跨JVM进程,只能用MQ,并且如果要用到一些延迟消息、顺序消息、事务消息等就必须要用MQ,以及如果并发量比较大,也需要借助MQ进行削峰填谷。

March 22, 2026 · 1 min · santu

如何实现百万级排行榜功能?

典型回答 关于排行榜,我们介绍过基于 ZSET 可以非常简单的实现: ✅基于Redis的zset实现秒级排行榜 但是,如果数据量很大呢?这个方案又会遇到哪些问题,以及该如何解决这些问题呢? 需要解决的问题 数据存储和管理(重要) 首先,第一个关键的问题,就是百万级用户参与排行榜的数据如何进行存储和管理,首先我们之前的文章介绍过,使用 Redis 的有序集合(ZSET)作为主要数据结构来存储排行榜数据是非常典型的做法,因为ZSET 提供了高效的插入、删除,尤其是按分数范围查询的功能。 但是,这里面需要考虑一个关键问题,那就是 bigkey 问题。 ✅什么是大Key问题,如何解决? 对于 Set 类型的 Value 值,含有的成员数量为 10000 个就已经可以算作是大 key 了,如果有100万,那妥妥的大 key。 那么我们就需要解决这个使用 zset 存储带来的大 key 问题。 排行计算和更新 作为一个排行榜,我们需要实时、高效的更新排行榜的数据,那么,如何处理用户分数的实时更新和排名计算,同时保证系统的性能和实时性,是一个至关重要的问题。 数据分页和查询效率 我们的排行榜,假如说要看比较靠后的排名,比如第50万到51万的排名的情况?(当然,一般很少有这种需求),那我们就要考虑当数据量庞大时,如何高效地进行排行榜数据的分页查询和排序,避免性能下降。 并发访问的问题(重要) 大量用户同时访问和更新排行榜数据可能会引发并发竞争和数据一致性问题。这个我们要如何解决? 容灾和数据一致性问题 如何保证系统容灾性,避免排行榜数据丢失呢?如果用持久化存储,那么一致性问题又如何保障呢? 解决方案 数据分片和分区(重要) 为了解决大量用户存在一个 ZSET 中出现的 bigkey 问题,我们可以将采用分片存储的方式,将原来分布在一个 ZSET 的中的数据,拆分到多个 ZSET 中,按照一定的规则进行拆分路由即可,比如按照日期、地域等进行拆分。 比如如果我要做一个全国的排行榜,那么我不需要把全国的数据都放在一个 ZSET 中,我只需要按照省份,把不同的省份的数据单独放到一个 ZSET 中,排出每个省的排行榜,然后需要查询全国的排行榜的时候,在进行一次跨 ZSET 的排序就行了。 比如我要查询全国前10,那么我就查询出每个省的前10名,然后再基于这么多个省的数据,进行一次综合排名就行了。 甚至我可以直接维护一个全国前3400的排名(全国有34个省级行政区),这里面的数据就是定时从省级前100的排名中取出来放过来的。这样就可以快速的获取全国前100了。 这里的省份只是举例子,你可以不用这些信息,就直接基于用户 id 的范围划分也可以的。 异步&批量更新(重要) 为了提升整体的吞吐量,我们可以对于分数的变化的写入操作,做成异步化的方案,只在用户分数变动时进行更新操作,而不是每次用户操作都立即更新排行榜数据。这样可以降低直接写入 zset 的频率,减少并发写入时的竞争。 同时也可以使用MQ 或者定时任务来处理批量更新操作,,例如每隔一段时间重新计算一次排行榜,或者删除一些不再活跃的用户数据,以控制 zset 的大小和内存消耗。降低实时更新对系统性能的影响。 ...

March 22, 2026 · 1 min · santu

Redis 如果挂了,你怎么办?

典型回答 这个题,一般是在你介绍完你的项目或者方案之后,因为你用到了 Redis,面试官就会问你,Redis挂了怎么办? 他不是想问你如何去恢复 Redis,这是运维干的事儿。那作为开发,如果 Redis 挂了,我们能怎么办呢? 首先,我们就是可以想办法减少 Redis 挂了的概率,以及降低挂了可能带来的影响,这主要就是哨兵模式、集群模式的一些东西了,这不展开了。 ✅介绍一下Redis的集群模式? 如果就是真的挂了,怎么办? 发现问题 首先我们需要有机制可以发现 Redis 挂了,最常见的就是加监控了,一般对于 Redis 自己可以做监控,我们在业务中也可以基于 Redis 调用的成功率做一些监控,当发现长时间不可用,或者超时之后,就可以认为是 Redis 挂了,就需要考虑应急机制了。 限流&降级 当Redis 挂了,并且我们已经发现了,之后就需要考虑这个使用 Redis场景的降级问题了,就是说 Redis 不能用了,我需要切换到其他的方案上了,比如说订单的秒杀库存扣减场景,一般是先在 Redis 中做预扣减。如果Redis 挂了,那我们就得把 Redis 给他降级掉,那就是不要再调 Redis 了,而是直接去调数据库。 但是你加 Redis 的原因是因为数据库扛不住那么高并发, 咋办呢、 这时候就需要限流了,通过限流的手段,让请求不要这么多的都打到数据库中,在前面给他拦住一些流量,虽然对用户来说体验不一定好,但是至少我的数据库没有被打垮,至少我还能对一部分用户提供服务的。 但是这些都是需要你提前就做好设计的,你要是一点设计都没做,等 Redis 挂了之后在做这些,那肯定来不及了。 所以,如果你的场景严重依赖 Redis,那你就需要提前做好这个降级方案,甚至需要配置一个开关,在 Redis 挂了之后,一键切换成不调Redis,并且开启限流。。。这个玩意在大厂中叫做预案。 一般来说预案和故障是关联的,当线上出现了某个故障,可以直接触发预案执行。 备份 Redis挂了,如果有一个备用的能顶上,那也是可以的。所以,很多 Redis 的部署都是主备形式的,备份实例平时不对外提供服务,只和主实例做数据同步,保证数据的准确性。 然后在主实例挂了之后,我们就可以快速的切换到备份实例上面来。这就是因为提前做好了热备的方案,就可以在出现故障的时候做故障转移。 其实这背后就是一种冗余的思想,在很多大厂中,冗余非常常见,就是为了应对这种突发状况的。 甚至有的备份是不同的架构的备份,比如备份到 Mangodb中。。。 本地缓存 Redis 主要是用来做做缓存的, 提升性能的,如果 Redis 挂了,说明缓存就没了,那么还可以考虑降级到使用本地缓存来抗并发。 当然,本地缓存存在不一致的问题,这时候就根据你的业务来看了,能不能接受不一致,或者说是不是宁可系统挂了,也不能接受不一致。。。

March 22, 2026 · 1 min · santu

Redis 的内存如果用满了,会挂吗?

典型回答 这个问题其实考察的是 Redis 的内存淘汰策略。 所谓内存淘汰策略,其实就是Redis 的内存淘汰策略用于在内存满了之后,决定哪些 key 要被删除。Redis 支持多种内存淘汰策略,可以通过配置文件中的 maxmemory-policy 参数来指定。 ✅Redis的内存淘汰策略是怎么样的? Redis 支持很多种内存淘汰策略,如: noeviction:不会淘汰任何键值对,而是直接返回错误信息。 allkeys-lru:从所有 key 中选择最近最少使用的那个 key 并删除。 volatile-lru:从设置了过期时间的 key 中选择最近最少使用的那个 key 并删除。 allkeys-random:从所有 key 中随机选择一个 key 并删除。 volatile-random:从设置了过期时间的 key 中随机选择一个 key 并删除。 volatile-ttl:从设置了过期时间的 key 中选择剩余时间最短的 key 并删除。 volatile-lfu:淘汰的对象是带有过期时间的键值对中,访问频率最低的那个。 allkeys-lfu:淘汰的对象则是所有键值对中,访问频率最低的那个。 因为有了淘汰策略,所以 Redis 即使内存满了,也不会立刻就挂了,而是会基于淘汰策略去移除一些 key来腾挪空间出来。 这里需要注意的是,即使是noeviction这种策略,也不会导致 Redis 立刻就挂了,如果满了,Redis 会拒绝写入操作,并返回 OOM command not allowed when used memory > 'maxmemory' 错误。 总结一下就是,Redis 本身设计上不会因为内存满而崩溃,但需要通过适当的配置来管理内存使用和处理策略,以保证服务的稳定性和性能。

March 22, 2026 · 1 min · santu

给第三方提供接口调用,需要注意些什么?

典型回答 我们在开发中,经常需要给别人提供一个接口进行调用,那么,我们在提供这些接口的时候,有哪些注意事项呢? 首先,我们提供的接口大致分为两种,一种是公开出去的接口,别人都可以申请调用的那种,还有一种是内部接口,只有内部人员才能调用的。 其实,不管是啥接口,都需要注意以下内容: 随便说两句:这个问题是一个粉丝提给我的,他说在别人的面试题文档中看到过类似的问题,但是那个答案一看就是 GPT 生成的,罗列了一堆正确的废话,想让我展开说说,以下是我的一些思考。大家可以看下和 GPT 内容的区别。 1、安全性:这个不管是内部还是外部接口其实都需要关注的,只不过有的时候内部接口可以不必要做的那么重。主要就是就是授权机制、数据传输的安全性这两个方面了。 授权机制的话可以是 API 密钥,也可以是认证相关的,比如 OAuth、JWT 等等。如果是需要和用户信息相关的,可能需要登录的话就需要 OAuth、JWT 这些,如果不需要用户鉴权的,可以直接用API 密钥来控制。 大家如果对接过一些开放平台就会知道,他们都要求你先在上面注册一个应用,然后给你发放密钥,你就可以通过这个密钥进行访问了。这个密钥,就是唯一能证明你身份的。作为 API 的提供者,我们就可以识别出来是谁在调用我们,如果遇到一些安全问题,我们就可以针对指定的密钥做限流、或者封禁。 然后在数据传输上,一般还会约定加解密、加解签,来保证数据的安全性和不可篡改性。这相当于是双方的一个握手,确保数据是从我这里发出的,中间没有经过别人的修改,并且即使别人拦截到数据了,他也无法拿到具体的明文内容。详见: ✅加密&解密、加签&验签做的事情一样吗? 2、访问控制:这个其实和上面的安全性有点像,也是安全性的一种,单独要提一下就是比较重要的,比如上面我们提到过的密钥,它不仅可以做调用者的记录,我们还可以做访问控制,不仅是前面提到的限流、还可以做一些权限管控,可以基于密钥来控制可以访问哪些接口,以及不能访问哪些接口。 3、通用性:当我们在给别人提供接口的时候,最好是能考虑通用性,最好是这个接口不是定制化的,而是一个有类似需要的人都可以调用的,这就要求入参中可能要传入一些标识身份的字段,比如密钥、比如租户 ID、比如产品码等等,可以方便我们后续做扩展。 如果一个接口足够通用,那么后续在做对接的时候,就可以减少很多的开发工作量,而且你的系统的复杂度也会大大降低。 4、方便升级:当我们提供一个接口给别人的时候,你要确信,这个接口不可能一成不变,所以,可能需要提前考虑好后期的升级问题。这里面涉及到很多问题,比如说要不要做接口的版本控制,如果做了版本控制,则可以做更加精细的版本的管理,如果不做版本控制,那么则需要考虑升级的兼容性问题。 5、接口语义要明确:这个点其实很多人会忽略,举个例子,比如你定义了一个金额,类型你用的 string,那么别人传参数给你的时候,单位是元还是分?你需要明确清楚,还有最典型的返回值的 success,到底是表示调用成功了,还是表示处理成功了?这里面的差别很大(处理成功则不需要再检查 respCode 等字段,但是调用成功可能需要检查。。。)。 有人说,这不是最基本的么,确实是,但是我见过太多人定义的接口不够明确了,很容易产生误解。非常非常多,所以,对外接口的注释、文档需要尽可能的详细。因为一旦最后出现故障要扯皮的时候,人家不会说自己测试不充分,而是会甩锅给你说你接口定义不够清晰。 6、错误信息屏蔽:如果我们提供一个接口出去给被人调用,不管是内部还是外部,都不建议把异常抛出去,一方面别人也看不懂这个异常,而且这个异常别人也没办法处理,一旦在页面上展示出来一个 NullPointerException 就很尴尬。。。 所以,在做系统间交互的时候,我们需要用错误码体系来代替异常,可以定义一套错误码给别人,所有的异常自己都吃掉,而不是抛给别人。 **7、自我保护机制:**当一个接口提供出去之后。就一切都变得不可控了,你根本不知道他会怎么调用你,所以你需要做好悲观思想,那就是做好足够的自我保护,一些基本的日志肯定是要打印的,然后一些边界值的校验也是必须的,还有就是一些限流、降级、熔断的机制你也需要考虑起来。 ✅为什么一定要做限流?不应该服务好客户吗?不应该是加机器吗? 8、RPC 接口特别注意:因为 RPC 的调用方式,别人往往需要依赖我们提供的API 做调用,所以,API 中有几个点需要注意的: 1、方法的入参和出参需要可序列化,即实现Serializable 接口,否则在序列化和反序列化过程中会报错。 2、方法的出参最好带上 success、respCode、respMsg 等固定字段,用来表示是否成功以及响应码和响应信息。 3、接口中尽量用包装类,而不是基本数据类型, 避免默认值导致误解。 ✅RPC接口返回中,使用基本类型还是包装类? 4、接口出入参中,不要使用枚举,而是直接使用字符串,避免升级过程中导致序列化异常。而且一旦用了枚举,新增一个枚举项的时候,可能会要求所有调用方都做升级,否则就可能会出现枚举转换异常,这个也不太好。 5、是否成功这个字段,要用 sucess 表示,而不是 isSuccess 表示。 ✅RPC接口返回中,使用基本类型还是包装类? 扩展知识 兄弟问题 ✅和其他公司做数据交互时,有什么需要注意的?

March 22, 2026 · 1 min · santu

留言给博主