事务

在系统运行过程中,可能随时随地都会发生意外中断:

  • 数据库软件或硬件故障
  • 应用程序崩溃
  • 网络连接断开
  • 数据库并发读写
  • 应用程序竞态条件

为了实现可靠性,整个系统必须处理这些故障,但是实现相对完备的容错机制工作量巨大。**事务(transaction)**一直是简化问题的首选机制。

分区

对于非常大的数据集,或者非常高的吞吐量,仅仅通过复制是无法满足需求的。我们需要对数据进行分区(partion)。

在MongoDB,Elasticsearch和Solr Cloud中被称为分片(shard),在HBase中称之为区域(Region),Bigtable中则是表块(tablet),Cassandra和Riak中是虚节点(vnode),Couchbase中叫做虚桶(vBucket)。但是分区(partitioning) 是最约定俗成的叫法。

分区主要是为了系统的可伸缩性

分区常常与复制结合使用,使得每个分区的数据存储在多个副本节点中。在保证系统可伸缩的同时,保证系统的高可用。我们在设计系统分区的时候通常需要同时考虑如何将系统的整体读写负载按照预期分配到各个分区。

asyncio loop的运行循环

通过run_foreverrun_until_complete方法可以让我们完成初始化的loop run起来。

其中run_until_complete是将需要执行的函数"Task"化之后再调用run_forever,而run_forever真正将loop **loop**起来是通过

1
2
3
4
 while True:
                self._run_once()
                if self._stopping:
                    break

来实现的。

数据的存储与检索

对于一个数据库来说,它要完成最基础的两件事情:当你把数据交给数据库时,它负责将其存储起来;当你需要数据时,数据库能够将指定数据检索并返回给你,即数据存储与检索

从数据库的视角来说,上边的两件事情一般会交给底层数据库存储引擎来完成。对于开发人员来说,选择一个合适的存储引擎能够为后续系统的建设非常重要。

数据模型与查询

对于应用程序开发人员来说,我们的编码过程很多场景下都是对现实世界的代码描述。这个描述过程可以理解为数据模型的构建过程。数据模型不仅影响着代码的编写方式(面向对象、函数式编程等等),它也会影响我们后续解决问题的思路。

在计算机系统中,我们常常通过构建层级结构来解构整个系统(例如计算机存储器的层级结构),一个复杂的应用程序往往会有多个中间层次,每个层次都提供一个明确的数据模型来隐藏更低层次中的复杂性。这些抽象出来的数据模型能够为构建整个系统的不同角色提供有效协作的基础。

常见和常用的数据模型,可以抽象为几大类:关系模型、文档模型和图数据模型。

代码如何在系统中运行

我们平常所编写的代码,无论是c代码、go代码、rust代码或其他代码,大都是以文本文件的形式存储在计算机硬盘上。以最简单的hello_world程序为例:

1
2
3
4
5
6
#include <stdio.h>

int main() {
		printf("hello world\n");
		return 0;
}