aerospike学习笔记

公司最近在将Memcached替换成Aerospike,整理了一下学习笔记。

Aerospike是什么

Aerospike是一个高性能的分布式Key-Value NoSQL数据库,可基于行随机存取,索引存放在内存中。数据存取可以在内存中或者SSD。

应用场景

一个典型应用是广告业务。作为服务器端的cookie存储来使用,这种情况对写入性能要求比较高。

Aerospike Architecture

如下图所示,我们可以将Aerospike看成4个部分:Client, Cluster, Server, Storage.

架构是Shared Nothing架构。Shared nothing架构(shared nothing architecture)是一种分布式计算架构。这种架构中的每一个节点都是独立、自给的,而且整个系统中没有单点竞争。在一个纯Shared Nothing系统中,通过简单地增加一些廉价的计算机做为系统的节点却可以获取几乎无限的扩展。Shared nothing系统通常需要将他的数据分布在多个节点的不同数据库中(不同的计算机处理不同的用户和查询)或者要求每个节点通过使用某些协调协议来保留它自己的应用程序数据备份 ,这通常被成为数据库Sharding。Aerospike的架构主要包括三个部分:Client, Cluster, Storage.

Client

我们通过Client可以对Aerospike Server进行数据的get/put。开发支持多种语言,包括C,Golang,Python,libevent等。Client能够监控Cluster的所有节点,并且能自动感知Nodes的更新,同时掌握数据在Cluster内的分布。Client具有一下特点:

  • 高效性:确保request能直接到相应的节点读写数据,减少响应时间
  • 稳定性:如果节点出错,不需要重启Client端
  • 连接池:Aerospike的C/S交互是TCP连接,Client会在内部维护一个连接池保持长连接(指在一个连接上可以连续发送多个数据包),这样可以有效减少频繁的Open/Close TCP操作。

Cluster

Cluster使用Paxos分布式一致(Paxos’ distributed consensus)算法,支持持久化一致性。数据随机非配到节点,可以最小化惊群问题。
注:惊群问题,举一个很简单的例子,当你往一群鸽子中间扔一块食物,虽然最终只有一个鸽子抢到食物,但所有鸽子都会被惊动来争夺,没有抢到食物的鸽子只好回去继续睡觉,等待下一块食物到来。这样,每扔一块食物,都会惊动所有的鸽子,即为惊群。对于操作系统来说,多个进程/线程在等待同一资源是,也会产生类似的效果,其结果就是每当资源可用,所有的进程/线程都来竞争资源,造成的后果:
1)系统对用户进程/线程频繁的做无效的调度、上下文切换,系统系能大打折扣。

Storage

Aerospike有两种数据存储模式:内存、闪存(SSD)。为了满足高性能,索引存放在内存中。另外数据的存储模式非常灵活,下面再说。

Data Model

NoSQL数据库一般称为schemaless(无模式的),也就是数据存储没有固定的模式。对于Aerospike来说,less-schema应该更恰当一点。数据存储模式就是key-value,只是对于value并没有特定的格式要求。Aerospike的数据组织模式如下图所示。key索引存放在内存中,数据结构是红黑树。value可以存放在内存或者闪存中,其中bin,我们可以类比成mysql中的字段。

namespace

namespace可以类比为关系型数据库的一个数据库或者多个数据库。namespace包括records,indexes和policies。policy规定了数据的行为,包括数据的存储方式(内存/闪存),备份数目,记录过期时间。下面是一个namespace示例。

1
2
3
4
5
6
7
8
9
10
namespace <namespace-name> {
# memory-size 4G # 4GB of memory to be used for index and data
# replication-factor 2 # For multiple nodes, keep 2 copies of the data
# high-water-memory-pct 60 # Evict non-zero TTL data if capacity exceeds
# 60% of 4GB
# stop-writes-pct 90 # Stop writes if capacity exceeds 90% of 4GB
# default-ttl 0 # Writes from client that do not provide a TTL
# will default to 0 or never expire
# storage-engine memory # Store data in memory only
}

set

我一般习惯将set理解为关系型数据库中的表。一个namespace可以包含多个set,set只是一个对数据的逻辑上划分,namespace中的数据可以属于某个set,也可以不属于set.

record

record是Aerospike中数据存储的基本单位,我们知道Aerospike是行存储,一个record就对应一行。record包括下面一些数据。
component | description
— | —
key | 通过key的hash值可以定位到record
metadata | record的版本(第几次更新)和time-to-live(ttl)
bin | 类似RDBM的字段。

每个bin包括一个name和object,object里面定义了具体的类型。如果是key-value存储的话,最后我们取出的数据就是返回一个bin数据结构。我们可以简单看一下Aerospke提供的libevent API来看bin的组织形式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
typedef struct ev2citrusleaf_bin_s {
ev2citrusleaf_bin_name bin_name;
ev2citrusleaf_object object;
} ev2citrusleaf_bin;

typedef struct ev2citrusleaf_object_s {
enum ev2citrusleaf_type type;
size_t size;
union {
char *str; // note for str: size is strlen (not strlen+1
void *blob;
int64_t i64; // easiest to have one large int type
} u;

void *free; // if this is set, this must be freed on destructuion

} ev2citrusleaf_object;

简单明了,就不解释了。