6.架构设计场景题

查看飞书原文 ↗3,761 字符
开场话术​
​
​
"这个功能涉及到多个业务模块,所以架构设计是核心考虑点。"​
​
"当时我们考虑了扩展性和维护性,设计了一套可复用的架构。"​
​
​
​
​
标准答题示例​
​
我们要做一个多租户的权限管理系统,需要支持不同客户的个性化配置。​
​
架构上我采用了分层设计:​
1.
数据层:统一的权限模型,支持租户隔离​
2.
服务层:可配置的权限引擎,支持规则自定义 ​
3.
展示层:组件化的权限控制UI​
​
具体实现中,我用了几个关键模式:​
•
策略模式处理不同租户的权限规则​
•
装饰器模式做权限拦截和日志记录​
•
发布订阅模式处理权限变更的实时同步​
​
前端用React+TypeScript,状态管理用Redux Toolkit:​
•
权限数据用Normalized结构存储,便于查询和更新​
•
封装了usePermission Hook,组件直接调用判断权限​
•
路由层面做了权限守卫,无权限自动跳转​
​
这套架构支撑了30+租户的个性化需求,代码复用率达到85%。​
​
​
​
​
常见追问及应对思路​
​
面试官: “你说的分层设计具体是怎么划分的?”​
​
​
📔
答题思路:详细说明每层的职责划分、调用关系以及如何避免耦合。​
​
我们是按照领域驱动设计(DDD)的思路做的分层,整体结构分为:数据层(Domain) → 服务层(Service) → 展示层(Presentation),每层只依赖下层,接口调用清晰,避免循环依赖。​
​
数据层(Domain Layer):​
定义业务实体、权限模型和核心结构,不涉及任何业务逻辑,只关注数据的结构和约束。​
interface Permission {
  id: string;
  resource: string;
  action: string;
  conditions?: Record<string, any>;
}

interface Role {
  id: string;
  name: string;
  permissions: Permission[];
  tenantId: string;
}
​
服务层(Service Layer):​
负责权限的具体业务逻辑,比如权限校验、角色获取、权限更新等,同时隐藏实现细节,对外提供清晰接口。​
class PermissionService {
  checkPermission(userId: string, resource: string, action: string): boolean
  getRolesByUser(userId: string): Role[]
  updateUserPermissions(userId: string, permissions: Permission[]): void
}
服务层内部也做了权限缓存、并发控制等处理,提升了性能。​
​
展示层(Presentation Layer):​
在组件中消费权限服务,结合 Hook 做权限渲染控制,不直接操作业务逻辑。​
const ProtectedComponent = ({ resource, action, children }) => {
  const hasPermission = usePermission(resource, action);
  return hasPermission ? children : <NoPermission />;
};
此外,我们还通过事件机制让服务层可以通知上层做界面刷新,保持了良好的解耦性。​
​
​
​
​
面试官: “多租户的数据隔离是怎么保证的?”​
​
📔
答题思路:从数据库、应用、前端、测试四个层级说明如何防止数据串租。​
​
多租户场景下,我们用到了强制型隔离机制,分为四层:​
​
数据库层面:​
•
所有数据表设计都加了 tenant_id 字段;​
•
所有 ORM 查询都自动注入 WHERE tenant_id = ?;​
•
对外查询提供只读视图,防止跨租户查询;​
•
敏感表额外做了行级权限控制。​
​
应用层面:​
封装了一个 TenantContext,让所有查询都自动注入租户条件,防止开发者遗漏。​
return this.db.query(
  sql + ' AND tenant_id = ?', 
  [...params, this.tenantId]
);
还统一对外暴露只带 tenant 权限的服务接口,避免绕过隔离逻辑。​
​
前端层面:​
•
登录成功后将租户 ID 存入全局 Context;​
•
所有 API 请求统一加上 X-Tenant-ID Header;​
•
页面路由前会做权限校验,防止用户跳转其他租户页面。​
​
测试验证:​
•
做了多租户账号并发操作的集成测试; ​
•
模拟跨租户非法请求(如改 header),验证服务端防护;​
•
使用 Postman/自动化脚本做了白盒渗透测试。​
​
这套方案上线后,我们没有遇到过一次租户数据串用的事故。​
​
​
​
​
面试官: “权限变更的实时同步是怎么实现的?”​
​
​
📔
答题思路:说明你如何兼顾响应速度与稳定性,提升实时性但不依赖单点。​
​
我们用了「WebSocket + 轮询兜底 + 缓存控制」三层方案,既保障实时性,又避免因连接问题导致功能不可用。​
WebSocket 推送:​
用户权限变更后,服务端通过 WebSocket 发送变更事件。​
websocket.emit('permission_updated', {
  userId: '123',
  changes: [...],
  timestamp: Date.now()
});
​
前端收到事件后:​
•
刷新权限缓存;​
•
判断当前页面权限是否变化,提示用户刷新或强制退出。​
​
轮询兜底机制:​
每隔 5 分钟轮询后端权限接口,对比版本号,有更新就替换本地权限数据,防止推送丢失。​
​
权限缓存策略:​
•
权限结果缓存 30 分钟;​
•
如果某个操作被拒绝,会立即强制刷新;​
•
页面切换或激活时,也会自动检查权限是否过期。​
​
异常处理机制:​
如果发现 WebSocket 断开,会自动降级为轮询模式。​
权限同步失败时,我们采用“最小权限”策略,避免权限过宽造成风险。​
​
这套机制在复杂权限场景下稳定运行两年,几乎没有漏同步的情况。​
​
​
​
​
面试官:“这个架构在大规模场景下的性能如何?”​
​
📔
答题思路:从服务端、前端、系统架构三层面讲清楚你做了哪些性能与扩展性设计。​
​
我们在用户量和租户量增长后,做了不少结构优化,确保性能可控、扩展性强。​
服务端优化:​
•
权限计算做了缓存:​
把用户、资源、动作作为三元组缓存结果,避免重复判断。​
const cacheKey = `${userId}-${resource}-${action}`;
​
•
数据库层面建了复合索引:​
tenant_id + user_id + resource 查询速度大幅提升。​
•
热点数据进 Redis:​
高频资源或管理员权限用 Redis 做集中缓存,避免打爆主库。​
•
权限继承做了图结构改造:​
不再递归查父角色,而是一次性 flatten 出用户所有权限。​
​
前端优化:​
•
权限判断用了 useMemo 缓存;​
•
页面首次加载时统一批量拉取所需权限,避免多个请求;​
•
路由切换时权限预先加载,提升页面跳转体验。​
​
压测结果:​
•
单个用户权限判断时间控制在 10ms 以内;​
•
实测支持 1000 用户并发权限校验;​
•
在 30 个租户、10 万用户并发情况下,平均接口响应时间 < 80ms。​
​
​
扩展性设计:​
•
使用微前端架构,不同模块可独立部署,按需加载;​
•
权限系统作为独立微服务提供 REST API,可供其他系统复用;​
•
所有策略都通过配置驱动,支持后期动态扩展。​
​
这套架构我们已经在多个 SaaS 项目中复用过,验证了稳定性和灵活性。​
​
​
​
​
💡 整体答题策略​
​
1.
画架构图:面试时可以在白板或在线工具上画出分层结构,帮助理解你的设计思路。​
2.
举具体例子:比如“租户ID如何注入 SQL”、“权限缓存 key 的结构”,能说明你真的做过。​
3.
考虑非功能需求:不要只谈功能逻辑,性能、安全、可维护性是考察重点。​
4.
准备代码示例:权限服务、租户隔离、权限同步等核心逻辑要能写出伪代码或简化版实现。​
​