跳表
跳表本质上是一种链表,允许您在其上进行二分查找。它通过添加额外的节点来实现这一点,使您能够‘跳过’链表的某些部分。通过随机投掷硬币来创建额外节点,跳表的搜索、插入和删除操作的时间复杂度应为 O(logn)。
用例
- LevelDB MemTable
- Redis SortedSet
- Lucene 倒排索引
跳表本质上是一种链表,允许您在其上进行二分查找。它通过添加额外的节点来实现这一点,使您能够‘跳过’链表的某些部分。通过随机投掷硬币来创建额外节点,跳表的搜索、插入和删除操作的时间复杂度应为 O(logn)。
用例
总之,在选择公共 API、API 网关或 BFF(前端后端)网关的工具时,我更喜欢 GraphQL,因为它具有尾随结果、批处理嵌套查询、性能追踪和显式缓存等功能。
JSON RPC | GraphQL | REST | gRPC | |
---|---|---|---|---|
用例 | 以太坊 | Github V2、Airbnb、Facebook BFF / API 网关 | Swagger | 高性能、谷歌、内部端点 |
单一端点 | ✅ | ✅ | ❌ | ✅ |
类型系统 | ✅,与 JSON 一样弱 无 uint64 | ✅ 无 uint64 | ✅ w/ Swagger 无 uint64 | ✅ 有 uint64 |
定制结果 | ❌ | ✅ | ❌ | ❌ |
批处理嵌套查询 | ❌ | ✅ | ❌ | ❌ |
版本控制 | ❌ | 模式扩展 | 是,使用 v1/v2 路由 | protobuf 中的字段编号 |
错误处理 | 结构化 | 结构化 | HTTP 状态码 | 结构化 |
跨平台 | ✅ | ✅ | ✅ | ✅ |
游乐场 UI | ❌ | GraphQL Bin | Swagger | ❌ |
性能追踪 | ? | Apollo 插件 | ? | ? |
缓存 | 无或 HTTP 缓存控制 | Apollo 插件 | HTTP 缓存控制 | 尚未原生支持,但仍可使用 HTTP 缓存控制 |
问题 | 缺乏社区支持和工具链 Barrister IDL | 42.51 kb 客户端包大小 | 多个端点的非结构化,便携性差。 | Grpc-web 开发进行中,140kb JS 包。兼容性问题:并非所有地方都支持 HTTP2 和 grpc 依赖 |
面试是员工寻找未来同事的过程,在此过程中,他们 寻找信号来回答以下三个关键问题:
以上任何一个关键问题都无法在没有良好沟通的情况下回答。 你的工作将被那些沟通能力比你更强的人取代。
领导者 = 激励自我牺牲的愿景者
。没有说服能力,领导者就不存在。Apache Kafka 是一个分布式流处理平台。
它的抽象是一个 ==队列==,并且它具有
它可以应用于
Kafka 使用零拷贝,CPU 不需要将数据从一个内存区域复制到另一个内存区域。
没有零拷贝的情况下:
使用零拷贝的情况下:
从外部看,生产者写入代理,消费者从代理读取。
数据存储在主题中,并分割成多个分区,这些分区是复制的。
如何序列化数据?Avro
它的网络协议是什么?TCP
分区的存储布局是什么?O(1) 磁盘读取
==同步副本 (ISR) 协议==。它容忍 (numReplicas - 1) 个死掉的代理。每个分区有一个领导者和一个或多个跟随者。
总副本 = ISRs + 不同步副本
Jun Rao 说它是 CA,因为“我们的目标是在单个数据中心内支持 Kafka 集群的复制,在那里网络分区是罕见的,因此我们的设计专注于保持高度可用和强一致性的副本。”
然而,这实际上取决于配置。
默认配置(min.insync.replicas=1,default.replication.factor=1)开箱即用时,您将获得 AP 系统(至多一次)。
如果您想实现 CP,您可以将 min.insync.replicas 设置为 2,主题复制因子设置为 3 - 然后使用 acks=all 生产消息将保证 CP 设置(至少一次),但(如预期)在特定主题/分区对可用副本不足(<2)时将会阻塞。
API 如何可能不够健壮且不可预测?
如何解决这个问题?三个原则:
客户端重试以确保一致性。
使用幂等性和幂等性键进行重试,以允许客户端传递唯一值。
使用==指数退避和随机抖动==进行重试。要考虑==雷鸣般的群体问题==,即服务器可能处于降级状态,突发的重试可能会进一步损害系统。
例如,Stripe 的客户端重试计算延迟如下...
def self.sleep_time(retry_count)
# 根据到目前为止的尝试次数应用初始网络重试延迟的指数退避。不要让这个数字超过最大网络重试延迟。
sleep_seconds = [Stripe.initial_network_retry_delay * (2 ** (retry_count - 1)), Stripe.max_network_retry_delay].min
# 通过在 (sleep_seconds / 2) 到 (sleep_seconds) 范围内随机化值来应用一些抖动。
sleep_seconds = sleep_seconds * (0.5 * (1 + rand()))
# 但永远不要少于基础睡眠秒数。
sleep_seconds = [Stripe.initial_network_retry_delay, sleep_seconds].max
sleep_seconds
end
AKF 规模立方体将扩展过程可视化为三个维度…
想要一个例子吗?去看看 Facebook 如何扩展其社交图谱数据存储。
SOLID 是一组设计原则的首字母缩写,帮助软件工程师在项目中编写稳健的代码。
S - 单一职责原则。一个模块应该只对一个角色负责,一个模块只是一个功能和数据结构的内聚集合。
O - 开放/封闭原则。软件工件应该对扩展开放,但对修改封闭。
L - 里氏替换原则。通过接口和实现、泛型、子类化和鸭子类型来简化代码的继承。
I - 接口隔离原则。将单一的庞大接口分割成更小的接口,以解耦模块。
D - 依赖倒置原则。源代码的依赖关系与控制流相反。我们架构图中最明显的组织原则。
结构化编程 vs. 面向对象编程 vs. 函数式编程
结构化编程是一种对直接控制转移的约束。
面向对象编程是一种对间接控制转移的约束。
函数式编程:不可变性。是一种对变量赋值的约束。
大数据集 ⟶ 扩展 ⟶ 数据分片/分区 ⟶ 1) 数据访问路由 2) 可用性副本 ⟶ 一致性挑战
任何网络共享数据系统只能拥有三种理想属性中的两种。
12年后,作者埃里克·布鲁尔(Eric Brewer)表示“2 of 3”是误导性的,因为
因此,当没有分区(节点正确连接)时,这种情况经常发生,我们应该同时拥有AC。当出现分区时,处理它们的步骤如下: