分布式思考:我们需要分片Shard(含分库分表)吗?

2022-04-15 00:00:00 集群 都是 分布式 巴菲特 瓶颈

## Shard是个好东西

Shard是个好东西,对于分布式系统,它将数据分开,存储在不同机器上。

这样,我们就可以利用到集群的多机,很好地进行scale-out。

Shard的管理会增加新的复杂度,但通过一些手段我们可以解决:

1. [Consistent Hashing]

2. 类似Consistency Hash的思想,采用固定数目的Slot,比如:[Redis Cluster]

3. 用更复杂的机制,在Shard的管理上,采用一个meta data store,来管理各个segment的转移、合并、删除等

## Shard有它的麻烦

Shard对于scale out是个非常好的方案,而且是性能如果到达瓶颈时的终解决方案。

但是,如果我们的某个操作,涉及两个Shard,就是大的麻烦,包括:

1. Join

2. Distributed Transaction

对于Join,我们要到两个机器上去拿数据,因此,还需要一个中心点,做聚合Aggregation操作,同时,如果其中一个Shard fail了,怎么办?

对于Distributed Transaction,当前主流做法是2PC -- Two Phase Commit。但是,这是个效率很低的解决方案,而且有单点故障。Google虽然通过Precolater做了一定程度的优化,即将undo(含redo)延后处理,来减少Latency,从而提高Throughput,但是,它仍没有解决单点故障的问题,同时代价还是很大(为了Isolation的支持,还需要通过分布式的硬件时钟,或者集中式的软件时钟来保证顺序)。

## 一般情况下,Shard应该是后的解决手段

软件学说里有一句名言:

在没有达到瓶颈Bottleneck时,不要随意优化Optimization

类似地,我认为:

在一个Shard(无Shard)没有达到瓶颈Bottleneck时,不要轻易地分片Shard

因为分片Shard带来的麻烦,如Join,Distributed Transaction,都是不可避免的(还包括上面的Shard管理的复杂度)。而如果没有Shard,那这些麻烦都将不用考虑,从而简化我们的分布式系统。

分布式系统并不只是一开始就应该立刻进行分片Shard,或者说,分布式系统并不等于Shard(而应该是性能问题解决不了才Shard、或者很多时候是后终Shard)。我们应该简化系统,在系统能解决问题的前提下,用简单的方法(甚至老式的方法)去解决问题,而不是一开始就高、大、上。

## 我们当前一个Shard(无Shard)的瓶颈达到了吗?

比如:我们的一个数据库服务器,我们发现它只能大支持100K qps,于是,我们就认为,它的瓶颈到了,必须Shard了。

对吗?

我们看一个正常的互联网应用,其访问基本遵从一个规律:大部分访问是Read,小部分访问是Write。

如果90%的访问是Read,10%的访问是Write,那么,我们完全可以用十个机器来做一个集群,每个机器都有同样一份数据,那么就算访问量大到10倍,即1M qps,只要每台机器能支持100K Write qps,我们是不是就不用Shard?

你会说,Write会破坏一致性,不能保证Write时,十个机器的数据都是一致的。

但如果解决了呢?

[BunnyRedis要解决Redis的一致性Consistency问题]就是尝试解决这个问题的一个实践(Half Master/Master)。即分布式下,不用单一master来保证数据的一致性。

你会再说,这个BunnyRedis不过是解决key/value,这个对于Key/value适用,对于Relational Database不适用。即在我的文章[BunnyRedis的一致性Consistency]里,我只解决了右半边的问题,没有解决左半边的问题,比如:Read Committed, Repeatable Read, Serializable这些问题。

是的,我正准备解决这些问题。至于如何解决,因为我还没有做出来产品,来证明我的观点,所以,不适合发表(Talk is cheap, show me your code)。

但是,我认为,这是可以用类似的解决方案进行解决的问题。

同时,我前面发表的一些分布式优化,你也可以参考一下,如果你的单Shard(即无Shard)在这些优化下,都能做到不出现瓶颈,那么,你就不必急着分库分表,做Shard。

* [分布式思考:我们需要fsync吗]

* [分布式思考:我们需要WAL吗]

* [分布式思考:我们需要磁盘吗]

* [分布式思考:批处理Batch是个好东西]

* [分布式思考:Locality是个好东西]

* [分布式思考:锁是个麻烦]

* [分布式思考:如何提高性能]

* [分布式思考:少就是多,多就是少]

## 我个人关于Shard的几个观点

1. 我们不应该在单Shard(无Shard)还没有到瓶颈时,就急着去做Shard,因为这会带来复杂性,特别是Shard之间有交互

2. 在瓶颈判断时,我们不应该用整体(read + write)的负载(overhead)作为判断依据,而应该特别关注write,因为read几乎是无限扩展的,难点在write

3. 我们不应该用master/slave(因此只有单一master)去作为必须Shard的判断,因为强一致不一定就是master/slave,还有half master/master

4. 我们应该让成为瓶颈的负载尽量小,而不应该让可能出现瓶颈的组件做过多的事,一个案例就是:Kafka模式和纯Raft的对比(下一文章会有描述)

5. 当Shard数据之间没有交互时,我们可以放心地、大胆地、自由地,去做Shard,这是Shard佳的应用场景

6. 分布式下的事务 不等于 分布式事务,i.e., 分布式 + 事务 != 分布式事务

7. 分布式 不等于 Shard,i.e., 分布式 != Shard

## 我理想中的一个BunnyRedis集群的极限

                                                   ** Your Redis Clients **

                                                             |
                                                             |  Read/Write commands
                                                             |                                                            

**********************************************************                           ********************            
*                    NIC for Redis Clients               *                           *                  *
*                                                        *                           *                  *
*                  bunny-redis 1 (local SSD)             *                           *  bunny-redis n   *
*                                                        *          ......           *                  *
*                       NIC for Kafka                    *                           *                  *
**********************************************************                           ********************

                                                |
                                                |  only Write commands
                                                |

    ****************************************************************
    *                                                              *
    *     NIC-1    ...     NIC-8                                   *
    *       (for bunny-redis)                                      *
    *                                                              *                     ****************
    *                                                              *        commit       *              *
    *                                                     NIC-1    *     -------------   *   broker 2   *
    *                                       (for broker2)  ...     *                     *              *
    *                                                     NIC-3    *                     ****************
    *                                                              *
    *                      Kafka broker 1                          *
    *                                                              *
    ****************************************************************

相关文章