|
2 | 2 | permalink: /overview/background/
|
3 | 3 | ---
|
4 | 4 |
|
5 |
| -小米云平台长期以来一直使用开源的[Apache HBase](https://hbase.apache.org/)来存储结构化/半结构化数据,并逐渐成为国内使用HBase最多的公司之一,同时也培养了一个比较有实力的HBase开发团队,前后共产生了6位[HBase Committer](https://hbase.apache.org/team-list.html),包括一位PMC成员。可以说,HBase在小米云存储中起到了举足轻重的作用,而小米也为HBase社区贡献出一份重要的力量。 |
6 |
| - |
7 |
| -然而,HBase并不是十全十美的,它的架构、语言、实现等决定了它具有一些难以克服的不足: |
8 |
| -* HBase实现采用的Java语言,虽然开发上效率比较高,但是运行性能并不如C/C++这样的语言。 |
9 |
| -* Java语言还存在GC(Garbage Collection)问题,GC时可能造成进程进入假死状态,对于Server来说就是无法提供读写服务,造成读写延迟出现突然增加,容易触发客户端超时,降低系统可用性。 |
10 |
| -* HBase宕机恢复时间比较长(分钟级),在这段时间内服务是不可用的。其原因是: |
11 |
| - * HBase使用分层架构,底层使用HDFS存储数据,上层的RegionServer仅仅是服务点(Serving Point)。为了保证数据一致性,HBase要求每个Region在同一时刻只能由一个RegionServer服务。当某个RegionServer宕机,必须选一个新的RegionServer来服务该Region。恢复过程中需要做较多处理,包括日志的传输、切分、重放,这个过程比较耗时。 |
12 |
| - * HBase依赖Zookeeper来探测宕机问题,而由于Java的GC问题存在,Zookeeper的session timeout不能设得太短,典型地设为30秒。如果设得太短,Java GC的假死机就容易造成session超时,触发RegionServer不必要的自杀。因此从RegionServer宕机到被发现,这中间可能就需要几十秒。 |
13 |
| -* HBase的分层架构使数据服务点和存储位置分离,对Data Locality不够友好,也是影响其读性能的一个原因。 |
14 |
| - |
15 |
| -以上这些原因造成了HBase的可用性和性能都存在一些不足,难以满足对服务可用性和延迟都很敏感的一些在线业务的需求,譬如广告业务。因此,我们急需一个不一样的系统,以弥补HBase的这些不足。在此之前,我们也调研过市面上存在的一些开源系统,包括[Apache Cassandra](http://cassandra.apache.org/),然而并没有一款能让我们满意。 |
16 |
| - |
17 |
| -基于此,从2015年开始,我们开始尝试自己开发Pegasus系统,并且从一开始就明确了我们的目标: |
18 |
| -* 高可用:系统必须是高可用的,即使在部分服务器挂掉之后,也能在极短时间(秒级)内恢复服务,尽量减少对用户的影响,要求服务可用度达到99.99%以上。 |
19 |
| -* 高性能:系统能够提供高性能的读写服务,并且在吞吐和延迟之间我们更倾向于低延迟。 |
20 |
| -* 强一致:系统对用户提供强一致性的语义,使用户编写业务逻辑时更轻松。 |
21 |
| -* 易伸缩:系统能够很方便增加或者减少机器节点个数,以应对业务负载的变化,并且这样的操作是自动化的,减少运维负担。 |
22 |
| -* 易使用:系统给用户提供简单易懂的库和接口,方便用户使用。 |
23 |
| - |
24 |
| -# 设计考虑 |
25 |
| - |
26 |
| -在设计Pegasus时,我们要在目标、实现难度、开发效率等方面做一些权衡和选择。关于这方面的考虑,我在ArchSummit 2016上做的分享中有具体介绍,参见[slides](https://www.slideshare.net/ssuser0a3cdd/pegasus-designing-a-distributed-key-value-system-arch-summit-beijing2016)。总的来说,包括这几个方面: |
27 |
| -* 开发语言:基于性能考虑,我们选择了C++。当然,我们也要忍受开发效率相对较低的问题。 |
28 |
| -* 数据模型:采用简单的key-value数据模型。这是为了简化开发,而且我们认为key-value已经能够满足大部分业务需求。同时我们又对key-value模型做了一些改进,将key分为了HashKey和SortKey,使其表达能力更强。 |
29 |
| -* 数据分布:采用固定Hash分布。相比Range分布和一致性Hash分布,固定Hash分布实现更简单,数据倾斜和可伸缩性可以通过合理设计Hash键和Hash函数、预设更多的桶等措施来缓解。当然我们后续还会提供partition split的功能,支持扩展分片数量。 |
30 |
| -* 存储介质:选择SSD。SSD的性能和成本都介于内存和磁盘之间,从业务需求和成本综合考虑,选择SSD是比较合适的。 |
31 |
| -* 单机存储引擎:选择[RocksDB](https://github.com/facebook/rocksdb)。因为RocksDB在LevelDB基础上做了很多优化,能充分利用SSD的IOPS性能和多核服务器的计算性能。我们没有必要自己实现一个。 |
32 |
| -* 一致性协议:选择[PacificA](https://www.microsoft.com/en-us/research/publication/pacifica-replication-in-log-based-distributed-storage-systems/)。相比更有名的[Raft](https://raft.github.io/),PacificA协议具有其自身的特点和优势。两者之间具体的区别,会有专门的文档来阐述。 |
33 |
| -* 故障检测(Failure Detection):和HBase不同,Pegasus没有使用Zookeeper来进行故障检测,而是在MetaServer和ReplicaServer之间实现了基于租约的故障检测机制。这样一方面是避免依赖外部服务Zookeeper,同时也更方便针对自己的系统进行优化。关于故障检测,会有专门的文档进行阐述。 |
| 5 | +# 设计目标 |
| 6 | + |
| 7 | +* 高可用:系统必须是高可用的。即使部分服务器宕机,Pegasus集群也能在极短时间(秒级)内恢复服务,尽量减少对用户的影响,要求服务可靠性达到99.99%以上。 |
| 8 | +* 高性能:系统能够提供高性能的读写服务,P99延迟需要在毫秒级别。 |
| 9 | +* 强一致:系统对用户提供强一致性的语义,使用户在编写业务逻辑时更容易。 |
| 10 | +* 易伸缩:系统能够很方便地扩容和缩容,以应对业务吞吐负载的变化。 |
| 11 | +* 易使用:系统给用户提供简单易用的库和接口,方便用户使用。 |
| 12 | + |
| 13 | +# 实现方案 |
| 14 | + |
| 15 | +在设计Pegasus时,我们在目标、实现难度、开发效率等方面做一些权衡。总的来说,包括这几个方面: |
| 16 | +* 开发语言:基于性能考虑,我们选择了C++。 |
| 17 | +* 数据模型:采用简单的Key-Value数据模型。这既简化了开发,也能满足大部分业务需求。进一步地,我们将Key拆分为了HashKey和SortKey两级,加强了其表达能力。 |
| 18 | +* 数据分布:采用固定Hash分布。相比Range分布和一致性Hash分布,固定Hash分布实现更简单,数据倾斜和可伸缩性可以通过合理设计Hash键、预设更多的数据分片等措施来解决。我们也支持[Partition Split](https://pegasus.apache.org/zh/administration/partition-split)功能来扩展分片数量。 |
| 19 | +* 存储介质:建议选择SSD。SSD的性能和成本都介于内存和磁盘之间,从业务需求和成本综合考虑,选择SSD是比较合适的。 |
| 20 | +* 本地存储引擎:选择[RocksDB](https://github.com/facebook/rocksdb)。RocksDB在LevelDB基础上做了很多优化,能充分利用SSD的IOPS性能和多核服务器的计算性能。 |
| 21 | +* 一致性协议:选择[PacificA](https://www.microsoft.com/en-us/research/publication/pacifica-replication-in-log-based-distributed-storage-systems/)。相比[Raft](https://raft.github.io/),PacificA协议具有其自身的特点和优势。 |
| 22 | +* 故障检测:和HBase不同,Pegasus没有使用Zookeeper来进行故障检测,而是在MetaServer和ReplicaServer之间实现了基于租约的故障检测机制。 |
34 | 23 |
|
35 | 24 | # 与HBase比较
|
36 | 25 |
|
37 |
| -Pegasus系统的最初目的就是弥补HBase的不足,而且上面也详细阐述了理由和设计思想。这里再从用户使用角度比较一下两者的区别: |
| 26 | +Pegasus系统的最初目的就是弥补HBase的不足,这里从用户使用角度比较一下两者的区别: |
38 | 27 | * 数据模型:HBase是表格模型,采用Range分片;Pegasus是Key-Value模型,采用Hash分片。
|
39 | 28 | * 接口:HBase的API接口功能虽然很丰富,但是使用也更复杂;Pegasus的接口简单,对用户更友好。
|
40 |
| -* 可用度:由于架构和实现的原因,HBase的可用度通常达到99.95%就不错了;Pegasus的可用度可以到达99.99%。 |
| 29 | +* 可靠性:由于架构和实现的原因(如Pegasus采用的本地存储、故障检测、使用C++语言实现等),Pegasus的可靠性通常优于HBase。 |
41 | 30 | * 性能:由于分层架构,HBase的读写性能不是太好,P99通常在几十甚至几百毫秒级别,而且GC问题会带来毛刺问题;Pegasus的P99可以在几毫秒,满足低延迟的在线业务需求。
|
42 | 31 |
|
43 | 32 | # 与Redis比较
|
44 | 33 |
|
45 |
| -其实Pegasus是不适合与Redis比较的,Redis是基于内存的缓存系统,与之比较性能肯定被吊打。但是我们发现,业务往往需要的不仅仅是性能,可能还有可用性、伸缩性等,所以比拼综合素质,Pegasus也是有其自身的优势的。 |
| 34 | +如果仅从性能角度比较,Redis显然是优于Pegasus的。但如果从性能、可用性、伸缩性、成本等方面综合比较,Pegasus也是有其自身的优势的。 |
| 35 | +与Redis进行比较的主要区别如下: |
| 36 | +* 数据模型:两者都是Key-Value模型,但是Pegasus支持(HashKey + SortKey)的二级键。 |
| 37 | +* 接口:Redis的接口更丰富,支持List、Set、Map等容器特性;Pegasus的接口相对简单,功能更单一。 |
| 38 | +* 性能:Redis性能比Pegasus好。 |
| 39 | +* 伸缩性:Pegasus伸缩性更好,可以很方便地增减机器节点,并支持自动的负载均衡;Redis的分布式方案在增减机器的时候比较麻烦。 |
| 40 | +* 可靠性:Pegasus数据总是持久化的,系统架构保证其较高的数据完整性;Redis在机器宕机后需要较长时间恢复,可用性不够好,还可能丢掉最后一段时间的数据。 |
| 41 | +* 成本:Pegasus使用SSD存储全量数据,而Redis需要使用内存来存储全量数据,Pegasus成本更低。 |
| 42 | + |
| 43 | +# 综合比较 |
46 | 44 |
|
47 |
| -我们在与业务的沟通中发现,他们很多时候对数据的性能和可用性要求都很高。在系统选型时遇到这些问题: |
| 45 | +业务在系统选型时,通常遇到这些问题: |
48 | 46 | * HBase虽然可用性高也易伸缩,但是性能不够好。
|
49 |
| -* Redis虽然性能好,但是需要大量内存,如果数据量太大,一台机器搞不定;如果采用分布式方案,譬如[Redis Cluster](https://redis.io/topics/cluster-tutorial)或者[Codis](https://github.com/CodisLabs/codis),在机器宕机故障情况下的可用性又不够,并且使用内存的成本也比较高。 |
50 |
| -* 一些用户想出了HBase+Redis的方案,即使用HBase做底层存储,使用Redis做上层缓存,写数据的时候同时更新HBase和Redis,读数据的时候先从Redis中读,如果读不到再从HBase中读;但是这样的缺点是:因为涉及两个系统,用户的读写逻辑会比较复杂,且同时写两个系统时容易出现一致性问题;一份数据要存储在HBase和Redis中,成本比较高;Redis机器宕机后造成部分缓存丢失,还是要从HBase读取,性能明显降低,服务质量下降甚至降级。 |
| 47 | +* Redis虽然性能好,但是需要大量内存,带来更昂贵的硬件成本。如果数据量太大,采用[Redis Cluster](https://redis.io/topics/cluster-tutorial)方案,在机器宕机故障情况下的可用性又不够。 |
| 48 | +* HBase+Redis的方案,即使用HBase做底层存储,使用Redis做上层缓存。该方案的缺点是:涉及两个系统,用户的读写逻辑会比较复杂;同时写两个系统,容易出现一致性问题;一份数据要同时存储在HBase和Redis中,成本比较高;Redis机器宕机后造成部分缓存丢失,此时从HBase读取的性能又明显降低。 |
51 | 49 |
|
52 |
| -Pegasus可以看做是HBase和Redis的结合体,它即保证高的可用度,又具有好的伸缩性,还具有相对不错的性能。如果业务对性能的要求不是太变态(譬如P99要求在1毫秒以内),那么可以考虑直接使用Pegasus。与Redis进行比较区别如下: |
53 |
| -* 数据模型:两者都是Key-Value模型,但是Pegasus支持(HashKey + SortKey)的二级键。 |
54 |
| -* 接口:Redis的接口更丰富,支持List、Set、Map等容器特性;Pegasus的接口相对简单,功能更单一。 |
55 |
| -* 性能:Redis性能比Pegasus好不少,Redis是在几十或者几百微妙级别,Pegasus是在毫秒级别。 |
56 |
| -* 伸缩性:Pegasus伸缩性更好,可以很方便地增减机器节点,并支持自动的负载均衡;Redis的分布式方案在增减机器的时候比较麻烦,需要较多的运维介入。 |
57 |
| -* 可用性:Pegasus数据总是持久化的,系统架构保证其较高的可用性;Redis在机器宕机后需要较长时间恢复,可用性不够好,还可能丢掉最后一段时间的数据。 |
58 |
| -* 成本:Pegasus使用SSD,Redis主要使用内存,从成本上考虑,Pegasus显然更划算。 |
| 50 | +Pegasus综合了HBase和Redis的优点,它既保证高的可靠性,又具有好的伸缩性,还具有良好的性能。 |
0 commit comments