分布式存储的七方面问题
故障检查,租约协议;
选主算法,primary uniqueness invariant,网络隔离,脑裂,双主,拜占庭故障,failfast/failstop,failover;
日志复制,RSM;
membership change,或者config change,主机上下线管理,扩缩容;
数据复制,data rebalancing,data recovery;
副本放置逻辑和副本路由逻辑;
primary和backup之间如何fence?
外部一致性,线性一致性;
pipeline,fanout,primary-backup,quorum-based,gossip;
分布式日志,active-standby架构,active-active架构;
……
1是指fsync的调用,以及和fsync地位等同的函数的调用。调用次数,调用频率,在多少数据上施加调用等。设备的带宽和利用率是否合理,fsync的调用怎么均摊到更多io次数和吞吐之上呢?
3是指读/写/空间的放大。怎么tradeoff,牺牲一个保住其他两个呢?
5是指WAL的5个LSN,分别为prepare point,commit point,apply point,checkpoint,prune point。
处于prepare point和commit point之间的数据需要group commit;
处于apply point和commit point点之间的提交数据需要apply到内存的数据结构之上以后对读可见;
内存数据结构需要以一定的调度策略存档于持久化设备, checkpoint就是存档点;
recover from crash需要从近的checkpoint点恢复到commit point;
而一段checkpoint完成,则截止该checkpoint的日志可以截断,因此存在一个不大于checkpoint的点,是为prune point,截止改点的日志和老的on-disk镜像可以安全删除。
因此这5个点始终保持一条约束:它们之间存在全序关系。
两个并发事务冲突(读写,写读,写写),应该怎么处理呢?加锁等待还是检测到冲突主动夭折呢?
已经提交的事务对数据库的影响,怎么对当前outstanding事务的读操作可见呢?
tuple-at-a-time:采用了迭代器的模式,当前迭代器执行get_next时,调用child算子对应迭代器的get_next获取计算所需的输入tuple,然后执行一段计算代码,产生一个输出tuple,发射parent算子。
full materialization:每个算子接收到全部的输入数据,计算出输出结果,交给下一个算子计算。这种方式类似于批处理。
vectorized execution:数据在内存中按列存储,以数组表示。选择数组的大小,让其可以在L1 data cache中装得下,然后执行树的每个算子执行tight for-loop按数组处理数据。这样即避免了full materialization过多的资源索取,又能避免tuple-at-a-time的处理单个tuple的overhead,同时对cache更加友好,减少spurious invalidation,提升speculative cache missing的产生。同时简单tight for-loop,编译器能更好点编译成高效执行指令,同时也能更好地填充CPU的指令流水,充分利用CPU的multiple issue的功能加速简单指令的处理。
相关文章