分布式思考:我们需要分片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 *
* *
****************************************************************
相关文章