102 lines
5.3 KiB
Markdown
102 lines
5.3 KiB
Markdown
|
|
## 统一异常管理:
|
|||
|
|
|
|||
|
|
首先我定义了 自定义异常类(BusinessException)全局异常处理器(GlobalExceptionHandler)并且自定义了一些错误码(ErrorCode)
|
|||
|
|
|
|||
|
|
1. 出现业务逻辑的时候 会抛出我的自定义异常类 然后传入相应的错误码
|
|||
|
|
2. 全局异常处理器会捕获这个 自定义异常类 并返回一个统一的响应结构给前端。
|
|||
|
|
3. 如果是未预料到的系统异常(RuntimeException),同样会被 GlobalExceptionHandler 拦截,返回固定的系统错误码(50000)和提示信息(系统内部异常)。
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
## Redis + Caffeine 多级缓存:
|
|||
|
|
|
|||
|
|
Redis 是一种高性能的分布式 KV 存储,支持丰富的数据结构和高并发访问。它能把缓存数据存储在内存中,单节点读写 QPS 可达 10 万,常用于做分布式缓存或分布式锁。 Caffeine 是 Java 主流的本地缓存库,运行在 JVM 内部,访问速度比 Redis 更快,但仅能在单个服务实例内使用,无法在多台服务器之间共享数据。
|
|||
|
|
|
|||
|
|
我在云图库项目中将二者结合,形成多级缓存:
|
|||
|
|
|
|||
|
|
1. 用户请求先查询 Caffeine 本地缓存
|
|||
|
|
2. 若本地缓存未命中,则查询 Redis 缓存
|
|||
|
|
3. 若 Redis 也未命中,则回源到数据库,并将查询结果写回 Redis 与 Caffeine 流程如图:
|
|||
|
|
|
|||
|
|
## 以图搜图功能集成(门面模式)
|
|||
|
|
|
|||
|
|
门面模式(Facade Pattern)是一种结构型设计模式,通过提供一个统一的门面接口,把内部复杂的子系统接口隐藏起来,从而简化客户端与子系统的交互,降低耦合度。
|
|||
|
|
|
|||
|
|
我在云图库项目的“以图搜图”功能中就用到了门面模式:
|
|||
|
|
|
|||
|
|
1. 我有多个独立的爬虫或 API 调用类,分别负责获取搜图页面、解析 HTML 脚本、获取搜图结果等
|
|||
|
|
2. 为了简化调用流程,我创建了一个 ImageSearchApiFacade 门面类,把这几个复杂步骤都封装成一个 searchImage 方法
|
|||
|
|
3. 外部只需一行代码 ImageSearchApiFacade.searchImage(imageUrl) 就能得到最终的相似图片列表,而不必关心内部分多个 API 去爬取、解析、获取搜索结果的细节。 这样做既减少了重复代码,也让功能调用更直观,符合“高层接口简化、子系统细节隐藏”的门面模式思想。
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
## 实时协作模块:
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
## AI 集成模块
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|

|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
# 朋友
|
|||
|
|
|
|||
|
|
## 距离算法
|
|||
|
|
|
|||
|
|
距离算法是一种用于度量两个字符串之间的相似度或者差异性的算法
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
## 分布式
|
|||
|
|
|
|||
|
|
Redis 是一个开源的、基于内存的 K/V 存储中间件。由于基于内存,其读写性能非常高,很适用于缓存。此外,Redis 支持多种数据结构、各类编程语言的客户端、支持持久化数据,其生态也非常广泛。
|
|||
|
|
|
|||
|
|
本项目中,我使用*** Redis 分布式 Session*** 来代替 *** Tomcat 本地的 Session 存储*** ,能够在分布式多机场景下保证获取登录用户信息的一致性。用 Redis 实现分布式 Session 的优点是非常简单方便,只需要引入 Redis 和 spring-session-data-redis 依赖,然后在配置文件中指定 Redis 的地址和 session 的 store-type 为 redis,即可自动生效,不用自己额外编码。
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
## TOP N
|
|||
|
|
|
|||
|
|
你提到使用优先队列来减少 TOP N 运算过程中的内存占用,能否解释一下优先队列的特点和在项目中的具体应用?
|
|||
|
|
|
|||
|
|
在项目中,使用**优先队列**来存储从**数据库中查询出来的 TopN **最相似用户。把**`相似度作为优先级`**,淘汰相似度小于当前队列 TopN 的用户,存入相似度大于当前队列 TopN 的用户,**将队列的元素个数始终维持在 N 个**,从而减少了内存占用。
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
## 接口幂等性
|
|||
|
|
|
|||
|
|
接口幂等性:对于相同的请求,无论调用多少次,结果都应保持一致。项目中主要就是对创建队伍这种请求如果连点多次会超出每个用户规定的创建队伍最大数量
|
|||
|
|
|
|||
|
|
**redission **是一个基于redis的**数据网络** 提供了开箱即用的分布式锁功能
|
|||
|
|
|
|||
|
|
- 获取锁:当客户端请求获取锁时,Redisson 会向 Redis 发送一个 SETNX 命令,尝试将一个特定的键(锁的标识)设置为一个特定的值(客户端标识),并设置锁的超时时间。
|
|||
|
|
- 争用锁:如果多个客户端同时尝试获取同一个锁,只有一个客户端能够成功设置键的值,其他客户端的 SETNX 命令将失败,它们会继续尝试获取锁。
|
|||
|
|
- 锁超时:为了防止某个客户端获取锁后发生异常导致锁永远不会被释放,Redisson 设置了锁的超时时间。当锁的超时时间到达后,Redisson 会自动释放锁,允许其他客户端获取锁。
|
|||
|
|
- 释放锁:当客户端执行完锁保护的操作后,可以主动释放锁,这将删除锁的标识键,或者锁的自动超时也会导致锁的释放。
|
|||
|
|
- 锁的可重入性:Redisson 支持可重入锁,允许同一客户端多次获取同一个锁,然后多次释放锁。只有所有获取锁的次数都释放后,锁才会被完全释放。
|
|||
|
|
- 锁的续期:如果一个客户端在持有锁时,锁的超时时间即将到期,Redisson会自动为锁续期,防止锁在操作过程中被自动释放。
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|