焦点关键词实战步骤示意图

Coinbase 内存数据库面试题 2026:90 分钟分阶段高分解法

Coinbase 内存数据库面试题 2026:90 分钟分阶段高分解法

Coinbase 内存数据库面试题 2026 在近期非常高频。
因此,你需要一套可复用模板。
此外,这里统一来源口径。
这是我们学员贡献的最新面经。
与此同时,本文按 2026年最新 标准复盘。

2026 面试流程深度复盘:Coinbase 内存数据库面试题 2026

首先,这题通常是 90 分钟。
因此,面试官会分 4 个阶段加码。
此外,时间戳单调递增是关键前提。
换句话说,你可以用追加写简化实现。

首先,第 1 阶段是基础 CRUD。
因此,你先写 store/get/delete
此外,要先讲清删除语义。
具体来说,删除后应返回空值。

随后,第 2 阶段是 CAS 更新。
因此,要实现 storeItemIfMatch
此外,判断对象是“当前可见值”。
换句话说,要先读再原子写入。

接着,第 3 阶段是前缀扫描。
因此,要实现 scanByKeyPrefix
此外,你要解释索引为何可扩展。
与此同时,要给出复杂度结论。

最后,第 4 阶段是历史读取与 TTL。
因此,会加 getItemAtTimestamp
此外,还会加 storeItemWithTTL
总而言之,Coinbase 内存数据库面试题 2026 的核心是“多版本+可见性”。

在 Coinbase 内存数据库面试题 2026 里,常见追问很直接。
因此,你要准备“历史点扫描”扩展。
此外,要说明跨 key 一致性口径。
换句话说,所有 key 都按 scan_timestamp 判断可见。

核心题目解析

因此,推荐的数据模型是两层。
首先,key -> versions[] 存版本链。
此外,维护一个全局有序 key 索引。
与此同时,版本链按时间追加即可。

具体来说,版本结构至少含四项。
因此,需要 timestampvalue
此外,需要 is_deleted 或空值墓碑。
与此同时,TTL 用 expire_at 表达。

但是,你要避免一个常见错误。
因此,TTL 过期后不应“回退旧值”。
此外,墓碑也不应回退旧值。
换句话说,只看查询时刻前的最新版本。

在 Coinbase 内存数据库面试题 2026 中,双时间戳很关键。
因此,get_timestamp 是目标历史点。
此外,timestamp 是当前操作时间。
具体来说,若 get_timestamp > timestamp,应拒绝或报错。

System Design 逻辑流程图

flowchart TD
A[接收操作与timestamp] --> B{操作类型}
B -->|store/delete/CAS/TTL写入| C[按key追加新版本]
C --> D[必要时更新有序key索引]
B -->|get/getAt| E[二分找到<=查询时刻的最新版本]
E --> F{版本在该时刻可见?}
F -->|是| G[返回value]
F -->|否| H[返回None]
B -->|scanPrefix/scanPrefixAt| I[在有序key中定位前缀范围]
I --> J[逐key执行历史可见性判断]
J --> K[返回有序结果集]

Python 参考代码(可直接改写为面试版本)

from __future__ import annotations
from dataclasses import dataclass
from bisect import bisect_left, bisect_right, insort
from typing import Dict, List, Optional, Tuple


@dataclass
class Version:
    ts: int
    value: Optional[str]          # None means tombstone (deleted)
    expire_at: Optional[int]      # None means no TTL


class TimeKV:
    def __init__(self) -> None:
        self.hist: Dict[str, List[Version]] = {}
        self.sorted_keys: List[str] = []

    def _ensure_key(self, key: str) -> None:
        if key not in self.hist:
            self.hist[key] = []
            insort(self.sorted_keys, key)

    def _append(self, key: str, v: Version) -> None:
        self._ensure_key(key)
        self.hist[key].append(v)

    def _last_version_at(self, key: str, at_ts: int) -> Optional[Version]:
        versions = self.hist.get(key)
        if not versions:
            return None
        lo, hi = 0, len(versions) - 1
        ans = -1
        while lo <= hi:
            mid = (lo + hi) // 2
            if versions[mid].ts <= at_ts:
                ans = mid
                lo = mid + 1
            else:
                hi = mid - 1
        return versions[ans] if ans >= 0 else None

    def _visible_value(self, v: Optional[Version], at_ts: int) -> Optional[str]:
        if v is None or v.value is None:
            return None
        if v.expire_at is not None and at_ts >= v.expire_at:
            return None
        return v.value

    def storeItem(self, key: str, item: str, timestamp: int) -> None:
        self._append(key, Version(timestamp, item, None))

    def deleteItem(self, key: str, timestamp: int) -> None:
        self._append(key, Version(timestamp, None, None))

    def getByKey(self, key: str, timestamp: int) -> Optional[str]:
        v = self._last_version_at(key, timestamp)
        return self._visible_value(v, timestamp)

    def storeItemIfMatch(
        self, key: str, cur_item: Optional[str], new_item: str, timestamp: int
    ) -> bool:
        current = self.getByKey(key, timestamp)
        if current != cur_item:
            return False
        self._append(key, Version(timestamp, new_item, None))
        return True

    def storeItemWithTTL(self, key: str, item: str, ttl: int, timestamp: int) -> None:
        expire_at = timestamp + max(ttl, 0)
        self._append(key, Version(timestamp, item, expire_at))

    def getItemAtTimestamp(
        self, key: str, get_timestamp: int, timestamp: int
    ) -> Optional[str]:
        if get_timestamp > timestamp:
            raise ValueError("get_timestamp cannot be greater than current timestamp")
        return self.getByKey(key, get_timestamp)

    def _keys_with_prefix(self, key_prefix: str) -> List[str]:
        start = bisect_left(self.sorted_keys, key_prefix)
        end = bisect_right(self.sorted_keys, key_prefix + chr(0x10FFFF))
        out = []
        for k in self.sorted_keys[start:end]:
            if not k.startswith(key_prefix):
                break
            out.append(k)
        return out

    def scanByKeyPrefix(self, key_prefix: str, timestamp: int) -> List[Tuple[str, str]]:
        res: List[Tuple[str, str]] = []
        for k in self._keys_with_prefix(key_prefix):
            v = self.getByKey(k, timestamp)
            if v is not None:
                res.append((k, v))
        return res

    def scanByKeyPrefixAtTimestamp(
        self, key_prefix: str, scan_timestamp: int, timestamp: int
    ) -> List[Tuple[str, str]]:
        if scan_timestamp > timestamp:
            raise ValueError("scan_timestamp cannot be greater than current timestamp")
        return self.scanByKeyPrefix(key_prefix, scan_timestamp)

专家备考策略与高频考点:Coinbase 内存数据库面试题 2026

因此,Coinbase 内存数据库面试题 2026 的备考要先抓主线。
首先,你要先讲“按序写入”收益。
此外,再讲“多版本可见性”规则。
总而言之,先语义后代码,成功率更高。

核心考点

  • 因此,CRUD 要保证读写一致。
  • 此外,CAS 要基于最新可见值。
  • 但是,TTL 过期后不能回滚旧值。
  • 与此同时,前缀扫描要有有序索引。
  • 具体来说,历史查询要区分双时间戳。
  • 总而言之,要清晰给出时空复杂度。

STAR 应对策略(BQ)

  1. S:因此,我接到分阶段内存库题。约束是时间戳单调。
  2. T:此外,我目标是先过功能。然后保证可扩展。
  3. A:与此同时,我采用版本链+有序 key 索引。并定义统一可见性函数。
  4. R:总而言之,我在时限内完成全部接口。还能回答复杂度与权衡。

总结与行动号召 (CTA)

总而言之,Coinbase 内存数据库面试题 2026 的破题法很明确。
因此,你先锁定语义。然后再写结构。
此外,你要用一套模板覆盖 CRUD、CAS、TTL、历史查询与前缀扫描。
如果你想做一轮实战模拟,可点这里:联系我们的专家进行一对一面试辅导
与此同时,你也可以补充基础阅读:权威算法参考