Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

移动端系统设计题库

章节边界:本章是逐题口述练习卡, 不重复移动端系统设计方法与完整图片示范或业务算法实现. 所有数字均为练习假设, 答题时必须根据题干, 埋点和设备测量替换, 不能背成固定参数.

学习目标与使用法

每题用 8 分钟准备, 5 分钟口述: 先补题干缺失条件, 再讲接口, 状态 / 时序, 一个算式, 失败恢复和验收. 预期证据是一页设计草图及一条可证伪的指标定义.

题目练习卡

统一异步契约: Async<T> 由调用方持有的 operation/handle 所有, 最终且恰好交付一次, 通过 Completed(T), Failed(error) 或 Cancelled 交付; cancel() 由该 owner 发起, 终止本地等待和对已离开 owner 的回调, 不承诺撤销已送达服务端的副作用. 表中 Async<T> 的 T 仅表示成功值, 错误均走 Failed(error), 取消均走 Cancelled. 各题示例可能混用 callback 与 Async<T> 两种示意: callback 贴近传统 Java/OkHttp 习惯, Async<T> 是统一抽象; 面试时能讲清「底层 callback -> 上层统一异步契约」的映射即可, 不必强求所有题目同一种签名.

题目关键接口与条件状态 / 时序示例估算 (均为假设)失败恢复与本题练习
1 图片加载bind(target, ImageRequest, callback): RequestHandle, handle 含 requestId/cancel(); callback 收 ImageResult.Success/Failure/Cancelled, wrapper 每次绑定生成 ID, 回调仅匹配当前 target, GET 可有限重试 (本卡为 callback 示意, 等价映射为 Async<ImageResult>)bind -> cache -> fetch/decode -> ready/failed/cancelled; 复用先 cancel/detach 旧 handle360×240×4=345,600 B/图; 12 张约 3.96 MiB 像素数据; 尺寸来自布局测量, 预算按低端机峰值内存, 命中率和首图 P95 调整切网, 半缓存, 错图, OOM; 固定测试集窗口内错图率 错 cacheKey 显示数 / 有结果显示的绑定数 = 0. 完整示范见 59.
2 埋点 SDKtrack(name, attrs, occurredAt): Accepted(queueId) / Rejected(reason) 仅入持久队列; flush(reason): Async<Uploaded(ackId)>, 429/磁盘/协议错误走 Failed(error), 事件 ID 去重, ACK 后删除event -> validate/redact -> dedup/sample -> durable queue -> batch/ack2,000 event/s × 500 B = 1,000,000 B/s, 约 0.95 MiB/s 原始写入; 采样率, 批量和压缩由丢失率, 队列水位, 耗电和网络实测调整磁盘满, 429, schema 冲突, 进程死; 关键事件与普通事件按可接受丢失率分级. 算法见 55.
3 断点下载enqueue(url, uri, etag): Task(id); pause/resume(id): Async<TaskState>; 成功值为 Completed(uri, checksum), RangeUnsupported/ETagChanged/Storage/Network 均走 Failed(error); 同一 taskId 的 resume 幂等PENDING->RUNNING->PAUSED/RETRYING->VERIFYING->DONE200 MiB / 4 MiB = 50 块; 块大小, 并发由吞吐, 随机写, 服务端连接限制, 电量测量调整ETag 变化, 磁盘满, URI 失效, 进程死; 画 Range, checkpoint, 原子 rename 时序.
4 IM 同步send(clientMsgId, body): Async<Accepted(serverMsgId, sequence)>, sync(afterCursor): Async<Page(messages, nextCursor)>, ack(id,type): Async<Acknowledged>; 错误走 Failed(error), clientMsgId 幂等, serverMsgId 去重send -> durable log -> accepted -> deliver -> local transaction -> ack; 缺口补拉假设 100 万 active users × 40 条/日 = 4,000 万 消息 / 日; 平均写入 4,000 万 / 86,400 ≈ 463 QPS, 峰值 463 × 15 ≈ 6,945 QPS; active users 和峰值系数由活跃埋点 / 峰值窗口调整ACK 丢失, 乱序, 重连, 重复; sequence 发现缺口. 完整时序见 59.
5 离线缓存get(key, policy): Value/Freshness/Miss; mutate(opId, baseVersion): Async<Applied(version)>; sync(cursor): Async<Page(nextCursor)>; 冲突 / 网络走 Failed(error), opId 幂等read local -> stale/fresh -> refresh; write pending -> sync -> applied/conflict10,000 × 2 KiB = 20,000 KiB, 约 19.5 MiB 实体; 索引 / 操作日志预留比例由数据库页, 离线时长和写放大实测调整过期, 冲突, 重复提交, 迁移失败; 为一种冲突定义权威端和人工介入点.
6 Crash / 日志 SDKrecordBreadcrumb(): Stored/Dropped; capture(exception): reportId 只做最小安全写; upload(reportId): Async<Uploaded>, 重复 ACK 仍为 Completed(Uploaded), 其余上传错误走 Failed(error), reportId 幂等crash -> minimal safe write -> next launch validate/dedupe -> upload环形 200 × 300 B = 60,000 B, 约 58.6 KiB; 条数 / 字段以崩溃路径耗时, 磁盘和诊断完整度测量调整损坏文件, 重复上报, mapping 不匹配; 写出 buildId 与符号化核验.
7 权限治理request(capability, rationale): Async<PermissionDecision>, 成功值为 Granted/Denied/PermanentDenied/Unavailable; resolve(): PermissionState 从持久状态和系统状态重建; 重复调用同一未决 request 不重复弹窗feature intent -> rationale -> system result -> granted/denied/permanent-denied授权漏斗需最少 曝光数,发起数,系统弹窗数,授权数, 授权率为 授权数 / 系统弹窗数; 状态规模示例为 12 capabilities × 1 current-state record/capability/host × 64 B/record × 3 hosts × 2 retained policy versions = 4,608 B, 约 4.5 KiB; 记录大小按实际序列化和保留策略测量调整旋转, 进程死, 永久拒绝, 策略变更; 持久化 capability × state × policyVersion, 并画拒绝后的降级旅程.
8 Routernavigate(route,args): Async<Navigated(destination)>; resolve(route): Resolved/NotFound, 参数, 鉴权或未注册均走 Failed(errorCode), 解析只读幂等, 鉴权中断可重试parse -> validate -> intercept -> resolve -> navigate/fallback500 × 200 B = 100,000 B, 约 97.7 KiB 元数据; 生成表与运行时注册按启动耗时, 包体和扩展频率测量未注册, 参数错, 登录取消, 旧链接; 给出可观测错误码与安全白名单.
9 短视频 Feedfeed(cursor): Async<Page(items,nextCursor)>; play(item): Async<FirstFrame>; preload(item,bytes): RequestHandle 可取消, 播放 / 解码错误走 Failed(error), 重复 cursor 请求由服务端游标语义去重page -> local DB -> visible item owns player -> preload/cancel -> release1.5 Mbps × 3 s / 8 = 0.5625 MB, 约 0.54 MiB/条; 预取深度由废弃流量, 首帧 P95, 网络类型和缓存命中测量调整decoder 失败, 切后台, 网络降级, 滚动跳过; 画 Surface/player owner 迁移. Media3 细节见 51.
10 登录刷新authorized(request): Async<Response>; refresh(refreshToken): Async<NewTokens>; logout(reason): Async<LoggedOut>; AuthRequired/InvalidGrant/Retryable 走 Failed(error), 同一 token epoch 的 401 合并为 single-flight, waiter 可取消401 -> single-flight refreshing -> waiters retry/logout; token 更新原子化峰值 100 个并发请求同时 401, 经合并应为 1 次 refresh, 最多 99 个 waiter; 合并窗口由 401 聚集度, 刷新 P95 和服务端限额调整refresh 失效, 响应丢失, 多进程竞态; 写出 waiters 取消和清理用户数据. 协议见 37.
11 设备指纹 SDKcollect(consentedSignals): Signals/ConsentMissing; evaluate(timeout): Async<Decision>, Unknown 是成功降级值, 超时 / 网络走 Failed(error); 请求带 nonce, 服务端结果按 requestId 去重但 Unknown 不重试放大consent -> collect -> normalize -> signed request/cache -> result/unknown30 × 100 B = 3,000 B, 约 2.93 KiB 原始字段上限; 字段数由授权率, 字段缺失率, 误报成本和传输开销调整缺字段, 超时, 篡改, 误报; 设计 unknown 降级, 不能宣称绝对识别.
12 配置 / 实验fetch(etag): Async<FetchResult>, 成功值为 NotModified/Config(version); 网络 / 签名错误走 Failed(error); evaluate(flag, subject): Variant/Default; rollback(version): Async<Activated>, 同版本 activate 幂等bundled default -> cached -> async fetch -> validate -> activate/versioned rollback200 × 1 KiB = 200 KiB 配置; 是否启动同步取决于关键 flag 覆盖率, TTID 和缓存命中测量签名失败, 过期, 分桶漂移, 服务不可用; 给出稳定 hash 与默认安全值.

题目 11 高频追问 (设备指纹采集 SDK)

  • 指纹熵 / 独特性评估: 如何度量采集字段的区分度与稳定性? 常用做法是算归一化熵与两两碰撞率, 并给出唯一设备识别比例; 单纯叠加字段会稀释信号质量.
  • 字段漂移稳定性: App / OS 升级后字段名或取值变化会让同一设备指纹漂移, 需要定义字段版本号与归一化映射, 并用升级前后同一设备的匹配率验证.
  • 反模拟器 / 群控 / 改机对抗: 模拟器与真机在传感器, 系统属性, 图形栈上存在差异, 采集侧可做特征校验与一致性检查; 服务端结合设备信任分数与行为信号, 不能只信单一字段.
  • Unknown 降级的误报代价量化: Unknown 是低置信度成功值而非失败, 要按业务口径估算放行后漏报与拦截后误报的代价, 用混淆 / 代价矩阵决定阈值, 不能宣称绝对识别.

追加题目: 设计一个风控决策系统 / 反欺诈引擎 (题目骨架)

  • 需求: 客户端采集信号 (设备指纹, 行为序列, 位置, 环境特征) 上报, 服务端综合规则 / 风险评分 / 模型给出 Allow / Challenge / Deny; 决策按 requestId 去重且可审计.
  • 关键 trade-off: 误报 vs 漏报成本 (拦截一个真实用户 vs 放过一笔欺诈, 用代价矩阵定阈值); 决策降级 (规则引擎或模型超时 / 不可用时按兜底阈值放行或转入人工审核).
  • 验收: 命中率 / 误报率 / 决策延迟 P95, 灰度分层上线, 事后复盘闭环 (申诉, 标签回流, 模型迭代).

统一答题检查

每题最后补: 指标定义 (分母, 窗口, 分位数), 故障注入矩阵, 灰度层级, 暂停阈值, 配置 / 协议版本和回滚 owner. 参数若没有设备, 网络, 服务端和内容数据支撑, 应明确回答 “先以此假设压测, 再按命中率, P95, 资源峰值调整”.

自测

任选两题, 限时 10 分钟各写一张卡. 合格证据: 接口有输入 / 输出边界; 状态图含至少一个异常分支; 算式带单位; 恢复方案覆盖进程死亡或响应丢失; 没有把示例数值说成生产事实.