产生 Hotspot 的根本规律在于“数据生而不平等”("Data is created non-equal"),就如同现实社会中人与人不同一样,数据与数据之间有着天壤之别:某些特定数据极度流行(Extremely popular),而绝大多数长尾数据则几乎无人问津。如果系统不幸将这些超高热度的数据划分到了同一个物理节点,该节点就会瞬时沦陷。虽然理论上采用完全随机分配记录(Randomly assign)的方式能够实现全局流量的理想均衡、防止 Hotspot,但这种做法同样存在致命缺陷——当随机存储的记录被查询时,系统由于缺乏任何路由先验逻辑,只能被迫向集群的所有物理节点发起广播查询(Scatter/Gather),开销难以承受。
面对单表定位与打散流量的需求,第一种经典方案是范围键分区(Partition by Key Range)。这种方式在现实生活中的对应物就是各类多卷成套的百科全书、字典或《十万个为什么》。整套百科全书在编纂时,会将所有词条按照字母或首字顺序排列,例如将词条 A 到 B 编入第一卷,Hodernese 到 Crest North 编入另一卷,每一卷就相当于一个独立的物理分区节点。该方案的优势极为突出:执行范围扫描(Range Scan)或检索相邻键(Adjacent Keys)时效率极高,查询客户端只需根据边界范围锁定 Node 1、2 或 3,便可在局部节点直接顺序拉取目标片段。
然而,范围键分区的软肋在于它必须依赖高度精确的先验知识(Pre-knowledge)。百科全书可以静态统计所有词条的前缀分布,并据此均匀地切出 12 卷;但是在真实的线上数据库中,面对动态注册的用户表,工程师在系统启动前根本无法预测以字母 A 开头和以字母 C 开头的用户究竟会有多少。一旦盲目按照固定字母跨度划分节点,极易引发严重的数据倾斜(Imbalance)进而诱发热点。不仅如此,很多系统会尝试采用连续递增的值(如时间戳 Timestamp)来做 Key Range 分区,这往往会引发灾难性后果:现实业务普遍存在强烈的时间局部性(Recency access pattern),最新写入的数据会被最高频次地读取,而最新读过的数据极可能被反复重读;若按 Timestamp 切分分区,集群所有实时的写流量和高频读流量都会被瞬时砸向承载最新时间范围的那台特定机器,使其瞬间过载。因此,Key Range 分区仅适用于具备充分先验统计信息且访问特征平稳的场景。
为了解决数据不均与倾斜问题,第二种业界推崇的方式是哈希键分区(Partition by Hash Key),常配合 UUID 使用。UUID 即通用唯一识别码(Universally Unique Identifier),其设计初衷是无论在世界的哪台机器上独立生成,都能在数学概率上保证绝对唯一。以经典的 UUID Version 1 为例,它的生成逻辑是抓取物理网卡的全球唯一硬件地址 MAC ID,再加上自 1970 年 1 月 1 日(Unix Epoch)以来的高精度时间戳字符串拼接而成。基于 UUID 进行 Hash 分区时,数据能够以极高的一致性呈均匀分布(Uniformly distributed),例如需要将数据散列到 1024 个分区,只需抽取 UUID 前 10 个 Bit 进行计算即可快速映射。然而这种方式也是一把双刃剑:由于哈希算法彻底打碎了物理键的原生排列顺序,数据完全随机离散分布,系统便再也无法支持高效的范围查询(Range Query)。
- **Key Range 分区优势**:天然支持高效的 Range Scan 与 Adjacent Keys 局部读取。
- **Key Range 分区劣势**:缺少先验分布认知时易倾斜;使用时间戳分区会导致当前节点产生写/读热点集中击穿。
- **UUID v1 生成机制**:底层由网卡唯一标识 MAC ID 结合自 1970-01-01 起算的时间戳拼装保证全球唯一。
- **Hash 分区权衡**:实现数据均匀分布(Uniform distribution),彻底打散存储倾斜,但牺牲了范围查询(Range Query)能力。
```mermaid
flowchart LR
accTitle: Compound Primary Key Mechanism
accDescr: Flowchart showing how Cassandra and DynamoDB use Partition Key to locate nodes and Sort Key to order data within a node.
subgraph ClientRequest["客户端请求"]
Req["User Activity 数据<br/>(UserID: Scott, Time: 10:00:00)"]
end
subgraph RoutingStage["分区路由阶段"]
PK["Partition Key: UserID<br/>(Hash 计算)"]
end
subgraph NodeStorage["目标 Partition 内部 (Node 1)"]
SK["Sort Key: Timestamp<br/>(内部顺序排列)"]
D1["Record 09:59:00"]
D2["Record 10:00:00"]
D3["Record 10:01:00"]
end
Req --> PK
PK -->|"定位至 Node 1"| SK
SK --> D1
SK --> D2
SK --> D3
```
```mermaid
flowchart TD
accTitle: Dynamic Partitioning Split Flow
accDescr: Diagram showing how a partition splits into two once it exceeds the size threshold.
```mermaid
flowchart LR
accTitle: Three Architectures for Service Discovery and Routing
accDescr: Shows Peer-to-Peer routing, dedicated routing tier, and smart fat client routing.
subgraph Option1["方案一:P2P 节点内省 (Peer-to-Peer)"]
direction TB
C1["Client"] --> N0["Node 0<br/>(处理请求/转发)"]
N0 -.->|"转发至目标"| N2["Node 2<br/>(数据实际所在节点)"]
end
subgraph Option2["方案二:独立路由层 (Routing Tier)"]
direction TB
C2["Client"] --> RT["Routing Layer<br/>(从 ZooKeeper 读取元数据)"]
RT --> N_Target["Node 2<br/>(存储节点)"]
end
subgraph Option3["方案三:智能胖客户端 (Fat Client)"]
direction TB
C3["Internal Fat Client<br/>(缓存全量元数据)"] -->|"直接单跳请求"| N_Dest["Node 2<br/>(目标数据节点)"]
end
```
在分布式系统分区寻址的实现中,ZooKeeper 承担着核心的元数据存储职责。如果将路由知识(Routing Knowledge)进行细分,可以拆解为两个层级的映射:首先是从 Key Range(键范围)到具体的 Partition(分区),其次是从 Partition 到实际承载它的 Node(节点)。这两个动态变化的对应关系,都是保存在 ZooKeeper 这种分布式协调系统之中的。与之相对的是从 Node 到具体 IP 地址的映射,由于物理或虚拟节点的 IP 地址变动频率远没有分区和键范围分裂、迁移来得频繁,因此这部分映射通常直接委托给成熟的底层 DNS(Domain Name Service)来解析处理。
```mermaid
flowchart LR
accTitle: 分布式分区寻址与元数据存储架构
accDescr: 示意键范围到分区、分区到节点由ZooKeeper维护,而节点到IP由DNS解析
subgraph ZK["ZooKeeper / etcd (Source of Truth)"]
KR["Key Range"] --> P["Partition"]
P --> N["Node ID"]
end
subgraph Net["底层网络解析"]
N -->|"DNS 解析"| IP["IP Address"]
end
```
这种机制实际上构成了服务发现(Service Discovery)的核心底座,其唯一的“真理来源”(Source of Truth)就是 ZooKeeper。不论是路由元信息的初始化还是实时更新,系统内的所有节点与路由组件都会向 ZooKeeper 进行同步。一旦某个数据节点宕机(Down),集群监控便会将最新的状态变更迅速刷写至 ZooKeeper,确保它始终掌握最新、最准确的节点分布全局视图。
[0:00] Scott Shi: Truth is defined by majority
[5:00] Scott Shi: Data is created non-equal
[20:00] Scott Shi: Engineers 是非常喜欢 immutable data 的
[40:00] Scott Shi: 基本上每一秒钟都会有机器挂掉
[40:00] Scott Shi: 网络带宽始终是最宝贵、最脆弱的瓶颈资源
[45:00] Scott Shi: move data more than necessary
[66:20] Scott Shi: 基本上大家刚开始自己设计的话都会把 Repartition 设计错
[67:05] Scott Shi: 没有必要用 Gossip 实现
Original transcript
[0:00] 今天讲这个replication今天讲replication Sorry,今天讲 partition.我是把这个顺序改了一下我是把这个顺序改了一下,就是先讲partition,再讲replication,因为partition相对简单。Partition 相对比较简单的一个问题,Replication 是所有,我觉得是基本上所有distributed system 相对比较出现各种问题的源泉之一啊实际上就是replication 基本上是主要源泉了,因为这个replication 是和data相关的。你data会有inconsistency,然后data会有各种各样的问题,当你有replication 的时候。然后其他的问题就是distribute system,其他的问题我们之前也讲过,就比如说那个network delay然后你出现了 process 、pause 啊然后你没有 single point to truth 啊,truth is defined by majority这也是distribute system中起到其他比较大的问题,但replication这个实际上是和data相关的计划是distribute system有各种各样的原因之一,也是最难的一部分,效率比较难的一部分,内容比较多。但是partition的话比较简单,所以我就先讲partition这部分。到时候我们讲完 partition 以后再讲 replication然后这个呢是Partition是这个Design Data Intensive Application的第六章然后他这块呢主要讲的是就是这里面这张其实涵盖了三个问题第一个问题是怎么样的partition 是吧?你可以用Krange partition 还是用Hash partition不同的 service 也实践了不同的方式第二个的话就是 secondary indexSecondary Index是有这个Global Secondary Index和这个Local Secondary Index,这是其中很大的一部分然后rebalancing也是一个问题,就是这个rebalancing很容易,如果你从来没有想过rebalancing的话,自己设计rebalancing非常容易设计错最后的话是Request Routing,所以这个partition是有四个问题啊,就是怎么样做partition,怎么样选partition k,怎么样做index,rebalancing,还有这个request routing,四个问题。这块我们叫Partition的,但是有时候也叫Sharding,有时候在这个SQL和MySQL叫Sharding,是吧?然后这个MongoDB也叫Sharding,然后在Elasticsearch,SolarCloud都叫Sharding然后在HBase里面有不同的 terminology,但是总体来说呢,partition是相对来说比较没有问题的,sharding其实本身也没有什么问题。嗯Partition不是必须的,但Partition通常原因呢,为什么要做Partition呢?是跟Scalability相关的。这个很多时候,如果你的公司的Data不是很大的话,你没必要做Partition。比如说最最常见的例子就是Airbnb啊我记得我17年的时候跟一个Airbnb的Infra Engineer 聊天的时候他们还没有 Partition2017年,2017年,Airbnb没有parkation你可以想到它的数据量有多小是吧你就看另一方面可以看到这个partition不是必须的partation 是就是scalability,就是driven,就是你因为有scalability的意思,所以它要partition其次的话,每个partition,任何一个partition,其实是自己的一个database。你可以认为每一个partition是没有意识到有其他partition的存在的是吧,就是从,如果我们自己做partition的话,它是没有意识到其他的partition存在的,它其实就活在自己的世界里,是吧,我们就说活在自己的世界里,它认为它自己管的就是这个data里面的所有data,所以就 partition 来说,但是从全局来说,这个 partition 只是它 data 的一部分,是吧,比如说你对 user table 进行 partition 的话,它只是 user table 的一部分就是这个 partition 值 user table 的一部分它具体怎么partation呢?可能是这个user table的1/10%这样子其次的话,partition这块是有多种partition方式的。有一种partition方式就是根据table来partition,是吧?比如说你把user table放上自己的partition里面然后把这个比如说你把这个就是Transaction table或Payment table放到另一个partition data里面partition 里面这个也是一种就是partition的方式好像叫这个叫Vertical partition,有一个Word叫Vertical partition然后我们今天讲的主要是Horizontal partition,什么意思呢?就是User table已经grow太大了,就是User table自己放一个partition已经放不下来,那我们必须把User table break down下来,就是放到不同的这个table里面这个是讲这个Horizontal partition为主的,就是把一个User table break成若干份,然后把它存起来,然后我再重复一下partition不是必须的
[5:00] 要求 partition 的原因是 scalability所以scalability 是你要 partition 的原因然后对吧,我们之前也讲过这个就是选database的时候,到底选SQL还是noseql?然后SQL和NoSQL的选择不应该根据scalability的选择但是 scalability 是决定你要不要 partition 的原因 是吧?所以如果你回答的时候就说我这次选 SQL 和 no SQL你可以说用scatability 但是很多时候scatability不是driven factorScalability-driven factor是说partition的,就是Scalability-driven factor,就是Scalability不是做SQL和NoSQL选择的那个driven factor然后这块的话就是给了一个例子就是partition和replication的不同Replication 是你把一个Datacopy 在不同的机器上,就是copy 多个地方,比如说我们举一个例子,就比如说这个858这个Record,就是KValue,是吧?它K是858,然后Value是Vhold the Truth to be Self-evident,是吧?所以这个replication就是同一份data在不同的node上这个里面这个方框表示node,同一份的两个不同的node上。所以这种情况下它就是node1, replica1和 replica2就是同一份代表不同的node,你知道吗?partition是什么呢?partition是把一个大的table转化成subsid, smaller subset为小table。是 partition在这个partition里面然后后面的话这个KeyRange比较大出于在第二个partition里面然后对于它其中每一份data,然后再replicate一下copy 一下,replicate,copy 一下,这样的话保证其中的一个node,任何一个node,比如说这里面随便任何找一个node,当掉以后这个 service 还是可以继续 serve 这些 document 的因为它首先 replicate 过一遍是吧然后其次的话就是 replicate 过一遍是吧把这个reliability,然后其次的话,这个replicate一般也是在不同的datacenter,这个replicate data center可能也比较close to you,所以你的lentency可能要improve但partition的话就是说一个node存不下来,所以把它切分成不同的小块,smaller subset,存在不同的node上就是replication和partition的区别最好的replication和partition的应用是kafkaKafka是相对来说主要就是handle replication and partition如果看到技术难点的话它大部分时间都在handle怎么样做replication, 什么样做partition所以 Kafka 这个是 replication partition 处理比较多的。好然后说如果你有一个大的,就是一个 big amount data, let's say we use user data,是吧? 我有 billion records,有 user data, 因为是 billion records,所以可能是有那你打算怎么样partition呢?那一个错误的做法是什么呢?就是把这个partition呢根据你要partition的数量来除以10来比如说你要排这层十分你要除以十来做partition 这是错的做法这个做法呢是错的啊,我们稍后会讲为什么是错的,但是这块的话就是说我们partition是需要有一些approach的是吧,就是比如说常见错误的话你就出于10这个是肯定是错的。然后其次的话,partation中可能常见了另一个问题你可能会有 hotspot,什么是 hotspot?就是你partition了以后收到data的read和read都跑到一个一个record里面一个replica里面你把data分成了十份,是吧?分成十份存在十个node里面但你所有的 read 和 write 都跑到其中一个 node 因为这个 data 是 create non-equal 是吧?这个 data 是 create non-equal 就是每个 data 是 data 和 data 是不一样的嘛 就和人和人不一样嘛Data 和Data 不一样的,有一份Data就 extremely popular,有一份Data就 extremely no one want to access所以如果你把 popular data 全部放在一起的话,对于这个 replica 来说只有其中一个replica就非常耗宝,其他replica就没有人访问。那这个是很大的一个问题所以呢,最好的呢,防止hostbot的话,就是这个record是random来防的,就是random来assign但是这个也是有问题的也是有
[10:00] 就是可能也有问题,就可能你即使只有一个record在一个notes上,可能也非常也就是 record 只在一个路上,那个 record 也可能非常 hot我们稍微看一个其中比较hacky的位置,就是Twitter是怎么样用比较hacky的位置来解决这种 hot spot好,然后其次的话就是,嗯,其次的话,当你把这个data进行partition的时候,比如说你现在是user table,你把它partition了100分,那我随便来一个user,比如说user scott,那我怎么知道我的data在哪一个record上,在哪一个弄得上这个的话是需要一些 logic 的所以你如果没有这个 knowledge 的话,你没有这个 pre-knowledge 的话,你可能需要把所有的 node 都 core 一遍所以这个是需要单独处理一下。我们来看第一个partition,就是proposing partition,就是partition by range key,这个最常见的就是百科宝典,就是这个十万个为什么,或者这种英语词条大百科是吧?然后你看的话,它其实就是根据TESC所有的词条,然后根据吃条的range来进行partition的然后它这种情况下比如说A到B是一个第一本书然后从什么从这个什么Hodernese,然后到Crest North是一本书是吧,它就是根据这个来进行partition的,这就是partition by wrench key,然后这个的话是有是有好处的,好处是什么呢?当你 range scan 的时候就非常容易,比如说你要找从 A 到 D 的这个 record,那你就知道从书里面,从 partition node 里面,从 node 1, 2, 3,和 4 的一部分找就可以了,就是当你要认识scan的时候非常容易然后其次的话,当你要fetch一些adjacent key的时候相对比较容易,就是也是rend scan 也是非常容易。但是呢,它难点是什么?就是它难点的话,你需要有 pre-knowledge 像这里面他编书的时候 他可能编的时候是全部编好了 然后根据这个根据这个词的这个前面有多少个字是吧根据它字的数量然后给它把它 chop 成了 12 分但是这十二份我们想做一个database里面,做一个user table进行partition。假设你user table进行partition的时候也是按username进行partition的首先你是没有 pre-knowledge的,你不知道你不知道以 A 开头的人和以 C 开头的人在你的 database 里面到底有多少是吧如果你这个你盲目的说这个我就把C作为一个node,然后剩下来什么,那就把自己人为的划分node,你的node很有可能是imbalanced,是吧?如果是imbalanced的话,那你有可能会还是会有hot spot然后这一点,然后其次的话如果你不用User ID的话,你需要用一个Consistent,就是一个连续不断的值进行value,你可能比如说用timestamp,是吧? 假设另一种可能是用timestamp但如果有time stand的话你会可能会发生另一种情况是什么的就是你所有的read和write都是在最新的那个timestamp node上因为你这个timestamp一般来说常见的data access pattern就是非常常见的data access pattern就是最新写进去的data会被马上读,然后最近读过的data会有可能再被读,就是这个data是有一种recency的read和read access的这个pattern的。所以你最新写进去data你可能会马上被读,然后你在这个data就是有这种,就是这个时间的这个,从时间方面是有一种一定的read和read是有一定的关联的,是吧。所以如果你用timestamp进行partition的话,你还是会有house spot。所以这个range key partition 是缺点和优点是比较明显的所以它比较适合,其实比较适合你有一些pre-knowledge,比如说这样的词作你有 pre-knowledge 的话,完全可以按它 pre-knowledge 按进磁组来进行 partition 这个是还是可以的。然后其次第二种 partition 方式就是用 hash key 来进行 partition 。Hashkate的话就可以用UOID来进行partition如果这块大家不懂的UOID的话要search一下UOIDUOID可以这么认为就是Unique Collegiate, Universal Unique Ideas这个ID generate 出来的时候是能 guarantee 它不管在哪里 generate 的,它能 guarantee uniqueness叫 Universal Unique Ideas为什么可以 Guarantee Uniqueness 呢?你可以这么讲就是把世界上所有的机器就是你 UUID 都是用机器在能把设置上所有的机器好全部拿出来,把摄像所有机器拿出来,然后把摄像所有机器拿出来以后,它机器有一个ID,Unical Identifier ID,叫macID,把那个 mac id 拿出来然后再把所有的timestamp拿出来,比如说,我们知道现在的uniquetimestamp是从1970年1月1号来进行计时的把所有的器材拿出来,然后在Concordinate Time Stamp, 然后这个值是Guarantee Unique所以这个值呢就是UOID version 1的来源
[15:00] 所以这个UID是,你可以想是不同,不管是在哪一个机器上generate,它是guarantee unique的。因为它可以非常简单地 map 到世界上所有机体组的任何一台,然后再加上从1970年以后到现在的时间到现在的时间 是吧 它可以guarantee uniqueness另一种常见方法就是,比如说对任何一个Record 来说,我生成一个 UOID, Universal Unique ID,然后把这个 UOID 作为 Hashtag 的这个作为hash key 是吧,因为它是个unioid嘛,所以它我们可以比如说,我要hash层4000分,我就看前面的,比如说我要hash层1024分,我就看前面10个bit 是吧然后跟他10个bit决定他具体在哪个partition上就可以这么简单的来做是吧这个UID hash有好处是什么呢?就是它是非常uniform distributed,但是它就不能像Krange partition一样,就是不能做efficient range query了,因为现在data就非常random distributed了。所以这个UID是常见的一种做法,也是现在比较鼓励做的一种做法然后这里面我再想提第三种partition的就是Cassandra的partition在Casanzar里面,它的primary可以定义是partition k加sout kpartition k加sadk我可以举个例子比如说我们在几周前谈讨论YouTube视频的时候,包括我们谈论slack的时候,当我们是用dynamo的时候,我们就说我们可以把partitionKate,就是纯userActivityRecord,我们可以把partitionKate作为userID,所以你所有的user record 因为它partition case 就是user id 是一致的所以你所有的user record 会到同一个partition然后在这个partition里面我们可以把这个sought key作为timestamp因为我们谈论的是user activity table 是吧我们可以把这个sought key作为timestamp所以在这个table里面你可以想象就是所有的user record 比如说scot user record 全部在那个partition 就是全部在那个node1里面然后我所有的user activity不管是看了一个新的video啊,还是我那个中断了一个video,还是readup,还是readdown是吧还是做了不管什么action那我说的Action 都是被SortKate的TimeStamp在这个table里面的所以这是CompoundKate,这种CompoundKate就是搬仓的这种作用吧它是partition key和sort key然后可以加起来作为Primary,可以Guarantee,Unique但是你决定 partition 的那部分是咱们的 partition case 是吧你决定Sought那部分可以用不同的来那个什么这样的话你不是啊它实际上是把两个functionality 给分开了嘛就是兼顾了partition的部分也兼顾了这个Range Search的部分是吧因为你有partition可以和Sought可以Range Search是吧比如说我可以找见我所有的Activity在昨天过去24小时的Activity 是吧我通过的UserID找见我在哪个Partition再通过Time Stamp来找见我过去24小时的Activity但是你这样的话用hash case达到不了的所以可以达到这个功能,所以这个Cassandra和Denymal是有这么一个compound的Primary Kit的设计。好然后我们接着谈这个housebot谢谢大家有两个问题,Kathryn说,Timestamp是不准,可能会前跳或后跳会麻烦,对Timestamp是有可能会前跳和后跳的,但是作为程序员来说你是不考虑那么多的就是很多时候前跳后跳就是非常非常counter case非常非常 counter case,可能千万分之一或一亿分之一。很多时候,程序员是不解决这个问题。那我们知道这个现在所有的操作系统,所有的Modern Operating System是不解决deadlock如果你有Deadlock的话就死进那里,就是Deadlock就是operating system and deadlock是说我不解决的,这实际上是一种你发生的概率和这个efficiency之间这个权衡是吧如果你这个一个事情发生概率是几百万分之一和几千万分之一你是不考虑的基本上是不考虑的然后你更多的是focus on 怎么样是你的机器运算的更 efficient我和刚才就是群里面不是有一个在那边读那个我还不知道他名字,在读那个Distribute System PhD 了,然后他还说他也说他当时给Hedge Fund设计了一个设计了一个 fault tolerant 的一个Hedge Fund的公司设计了一个Fall Tolerant的一个系统但是因为Lintensive太高了所以不用所以他们最后就开始放着买了一个非常贵的router 是吧反正roter坏了以后再换一个roter用钱解决这个问题了所以我觉得new guides来说相对来说new guides
[20:00] 经验比较欠缺的后想那我们千万分之一的比如说Devlog会怎么处理那我们是不是应该处理,那怎么处理?我觉得相对来说嗯有更多经验的话,你会知道,如果这个事情发生的概率是千万分之一,很多时候是不处理的。就是你不会牺牲你的一分身谁去处理这个千万分之一或上亿分之一发生的概率的事情所以这是为什么所有的operating system都不考虑所有的operating system是不考虑deadlock你自己写server code的时候是不考虑timestam会前跳或后跳的但这个事情发生了以后,你可以把这个timestamp向前跳或向后跳作为debug的一种就是一种可能性但你写扣的时候是不考虑的还有一种常见的不考虑的东西是我刚刚想到已经忘掉了好谢谢大家谢谢大家好好我一下忘掉了,就是很多东西你是不会考虑的,就是因为它发生的概率太低了,它是理论上的可能性这种东西就是只是说你发生了以后只是说哎这个事情发生了,导致出现了一个 exception,出现了一个 outage,然后我们分析 outage的时候分析可能的原因是用自己来分析的然后第二个问题是partition和sharding有什么区别partition和sharding指是同一个东西啊它只是terminology 不一样只是word 不一样好,那我们就接著聊。在Extreme case的话,你说的Red和Red可能是一个SIM case,是吧?比如说你这个就是Twitter account,说的Red和Red可能是,就是说川普突然发了一个新的Twitter,是吧?前两天不是这样,不管是川普还是奥巴马的Twitter全部被hack掉了,但是假设说所有名人全部发了一个Twitter,是吧?你的这个Rate和Rate都是CMK 你所有的人都要看他的Twitter那你就这个data的volume就非常非常高那这种情况下怎么办呢这个做法应该是Twitter这么搞过的就是Twitter为了这个就是compensate their highest quality workload呢他是怎么做呢?他是把所有的这个K呢,后面加了两个digit,比如说这个Trump,现在Trump是作为一个这个这个Twitter是吧,Trump发了Twitter一页川普发了一个Twitter,就是1是吧,这叫Twitter number是1是吧,那我们在这个1后面加两个0,这边是100,然后系统加两个0,叫100那你读的时候你可以从这个100到199之间读任何一个Twitter 是吧?因为这个因为这个Twitter读了,你发出去的时候不可以modify的,所以这个Twitter是我们叫这个设计叫immute form,就是你发出去Twitter以后你是不能modify 是吧?所以你读100到199任何一个Twitter都可以但是写的时候,川普写的时候,在推特写的时候,在系统内部的时候,他其实是把一copy 到 100, 101, 102 到 199所以它这个写的 amplification 是 100但是他读的时候你从任何一个100到199之间读都可以所以这种方法是可以有效的减少这个case good的那你怎么决定,可能会有人问,那你怎么决定从100到199,哪一个partition里面读,从哪一个Twitter里面读,你可以把,比如说你有User有UID是吧,你可以把UID的最后100个数,然后磨100是吧,然后看从哪一个读,反正100和1999是完全没有任何区别是吧任何100个里面都没有区别它这个有一个前提是这个data是不能mute如果你这个datamodify了那你如果 modify 的话,那你就就麻烦了。比如说你 modify 了。比如说你这个 data 之前 Tom Twitter 一写了一个 A 是吧? 然后把这个 A 改成 B 了。把A改成B了以后,因为你是这个推特还是同一个推特,所以你这个A改成B必须在这100个里面全部改了那你对他谈 consistent如果你只改了其中一部分,那你作为reader的话,你读的data可能是steal data如果你想出最新的电厂,你可能要把100到199全部都读一遍然后找见最新的那个Data,才是可能最新的Data所以这也是一些原因,比如说这个Twitter做成Inmutable,我觉得纯粹是一个工程学的角度,从工程学的角度真的是非常方便,因为Engineers是非常喜欢Inmutable data的,能减轻很多很多的困难和麻烦。谢谢大家所以是这样子,然后这是一种trade-off,因为它我觉得Twitter能做这个事也是因为它这个Functionality就不支持Modify Twitter 是吧,它Data是Inuitable的,所以它可以做这个事。但是大部分时候是语问,大部分Service and data都是可以更改的,可能做这个的话就没有必要。其次的话,Twitter的,它确实这个Twits的这个read量就是,它有非常明显的 hotspot 所以它这个推特的cashing 和这个推特的这个Twitter的caching和Twitter的
[25:00] 这个你都得不做了Twitter caching和Twitter的这个houseborder,怎么样把houseborders翻到的数据也做得不错然后这块有人问的话说微博的Edit History的话,Modify原坡的话觉得这块可以怎么处理我觉得这个处理其实也比较简单你就是Twitter1 比如说川普发了一个Twitter e,当发Twitter,Twitter在把e-modify的时候,不要把它当成e嘛,你就直接,你看起来,visualize的时候好像是e-modify了,但是实际上就create一个新的Twitter,是吧?叫 Twitter E' 是吧?或者 E' 是吧?然后你再做进来到时候读的时候你看是读 E 还是读 E'那你可以做一些东西让它不能就是实践的是immutable的,所有的data是immutable,但是别人看起来好像是multable,就modified了一个data,但是你其实可以把它做成immutable data也是可以的好然后有一个问题说, Kafka 是作为Database的Master控制所有的Node吗?Cafa 不是一个 database 然后一个 node 最大的 QPS 是多少呢?嗯Jobbox做了一个 Kafka 的 throughput我们先一个问题回答:Kafka 不是一个 database, Kafka 是一个Message Queue 是吧 或者是一个Publisher Subscriber System 或者是一个叫Streaming System它实际上实践的时候它是做了replication和partition它是做了replication和partition,它就是实践了这两部分,replication和partition所以 Kafka,如果你只想了解replication和partition,就是系统中的两个概念你最好的就是研究 Kafka,所以 Kafka 的 replication partition 做的是不错的,因为他只做这两个方法。它只是把所有的Message replicate 一下,然后 partition 一下,它不是一个 database我去年参加 Kafka Conference,他们一直在Branding,他们做这个Marketing,销售想把它们变成一个Database,但它们不是Database。我觉得任何想把 Kafka作为Database的人我觉得应该是没有在这个distribute system 里面去过确认我觉得 Kafka 我个人觉得是不可能做成一个database的他们想做成database 但他不可能做database 我个人觉得那 Kafka Node QPS 做啥呢? Kafka Node QPS Job Box 做过一个research它这个QPS 它其实不是做QPS 它做了throughput per secondSuper per second 我记得Jobox当时做的是64MB/s就是如果一个 Kafka Single Node一个 Kafka Topic Single Node大概 throughput是64到128MB/s这个我觉得非常好理解 因为这64到128MB/s你可以认为就是一个Disk的throughput的最大限因为 Kafka指出replication and partition 其实其实它overhead非常低,所以它这个Kafka的QPS,其实没有QPS是说,因为你毕竟和Kafka的topic size和message size有关,所以Kafka的这个throughput per second就是约等于disk的suport per second 那就是大概100多MB/sJobbox有一个文章,专门写这个,如果感兴趣的话可以搜一下,花了很多时间做research,然后最后在这个threshold,其实就是和这个disk的threshold相关。像一只啊 我觉得挺有趣的好然后这个第一个问题就讲完了,就是partition里面怎么样选k,然后我们有两种partition的方式,一个是hash partition,一个是range krange partition然后讲第二个问题,Secondary Index。Secondary Index对于DenmoDB或者CassandraDB,Secondary Index是很有趣的一部分。我这块会不停的提DenomDB,因为我觉得个人觉得这个DenomDB确实是在MySQL,就是SQLDB里面,就是Relational Database里面,非常具有革命性的一个创新。DynamoDB 非常具有革命性的创新它就是有很多设计思念理念都非常好,就是非常适合distribute system包括看别人写distribute system,DynamoDB和Dynamo-like DB都是重点研究的对象,因为它这里面确实有很多很好的概念包括以后很多DB也是集去DenemoDB设计里面更改了一些地方所以这个DenableDB可以认为是NodeSQL中非常值得研究的一部分但是你会看到我非常很少提什么GraphDBDocument DBL 算是会比较耍题,我觉得这个其实它这个理念创新上来说,我觉得是没有DenimalDB这个理念创新更多的。所以DenimalDB,包括你看其他人写的这个文章写了很多科普的文章,不然科普的还是比较深的文章的话,Dynamo确实是非常值得研究的一个database,就除了relationals
[30:00] 以外,是非常值得研究的因为在DenableDB里面,很多时候是一个partition key你可以认为是个KValue Lookup,是吧?这个里面K就是191,然后这个record就是一个JSON File作为JSON File的时候,你可能就比如说这种情况下,我们就是存车的record有Honda,Fold,Audi,不同车record,不同color,不同location在你读的时候的话,很多时候你是不知道它的kid,是吧?你只有知道191才能读到这个record但是如果你不知道191的话,就读不到这个record所以你希望能search一下,就像sql 样的search一下比如说你空间color来search一下哪些车是红色的,是吧?哪些车是黑色的当你要search的时候,你不是用primarykid search你不是用Primary可以search的话,就需要有个SecondaryKit来做Index,Index就是保证你以后search可以更快一点。那你要用SecondaryKit index的话,它现在有两种Index,因为它是Distribute database,所以你有两种方式做SecondaryIndex,一种是叫LocalSecondaryIndex,或者它书里面有个字叫document secondary index一般叫local secondary index 都可以什么意思呢?就是说如果我们只看partition0的话你可以认为假设你想把partition0想成一个MySQL的话它这里面所有的record它的local secondary index其实就是用了MySQL的index就是非常简单用MySQL的index就是说它不care其他的partition它只对它自己内部的partition的data进行index所以这种情况下,当你insert一个比如说当你insert一个rad新加一个rad加一个新的radtoyota 是吧那你只在这个rad里面增加一毫就是比如说新的radtoyota是209 是吧你这块就加一个新的209你不需要去其他地方进行index然后这块也是一致的,比如说你这块先加了一个siver,siver,比如说posh是吧,你加个siverposh,然后你这块的话就把siver加一个posh是吧,比如说407啊什么siverposh,你index的时候只有local index,你是没有global index,这是local index,就是你写的时候是非常快嘛你加一个Record,你只要在自己的partition进行update就可以了你比如不管你在哪个partition,只要update自己的partition就行了你这个写是非常快的但你读的时候,你需要去把所有的地方都读到你不能只读一个partition你需要去读所有的partition比如说你要找所有的红色的card那你需要把所有的partition里面然后Red的那个Record全部读出来才能读到你所有的Data才能找到所有的红色的卡所以你这个Performance的效率读是很低的但是你写是很快的另一种相似的呢另一种不一样的叫Global Secondary IndexGlobal Secondary Index是不一样的 是吧它实际上呢它很多时候它那个Secondary Index是有在一个完全不同的Table上它有的时候是和这个Partition绑在一起的甚至有的时候它自己的一个这个Global Secondary Index是自己的一个table有可能就是看你怎么实践了看系统看怎么实践了它的想法是什么呢就把所有的Secondary Index放一起你比如说你不管如果你只用Global Secondary Index你不管在哪一个partition里面insert了一个新的data比如说你是Red Toyota你加了一个新的Red Toyota你都要去同一个地方一个Unified的地方去Insert Record这种情况下你比如说就到这个Partition 0里面在这个Red的Index下边加一个新的这个Toyota这个车的这个Key加到这里面这是Global Secondary IndexGlobal Secondary Index就是直观的看你读的时候你只要到一个地方读就可以了比如说你要找点说颜色为红的车那你只要到这个partition 0就是存颜色为红的这个partition里面就可以读到所有的record就知道它record在哪了一次读就可以了但你写的时候你比如说你这个写的时候大部分partition都上千个partition所以10个到上千个partition都是很常见的上万个partition也有的但你写的时候你上去在任何其他地方就是任何其他999或者9999个partition写的record你都必须到partition 0 里面去update 一下这个red 是吧那你这个效率就比较低嘛就是相当于是你要做两个transaction一个transaction在partition x 上另一个transaction在partition 0 上这是一个其次的话这是只是一个secondary index 是吧如果你这个row里面有10个secondary index 是吧你不仅对color进行index 对location进行index
[35:00] - Yes. You can do make index, do 10 fields index Your blood will be in different places So you insert a record, you can insert a partition in but you can also update the 10 secondary index in the different partition. You have a right, you have a right amplification. It is proportional to the secondary. proportional to your global secondary index of the number, is it? So this index is too much, this is written. Thank you. You can write any record in the 10th partage. The effect will be very low. So, because of this reason, I remember DynamoDB in Secondary Index was 5. You can't have 5. When you set up a 5th secondary index, you might want to break the table more quickly. preconceited. Thank you. - Huh? And then the Global Secretary Index is It's more efficient, but it's more efficient. Because, for example, if you have a record, you have a record, you have a record, you have a record, you have a record, you have a record. 5个 global secondary index, so you have to write 6 partitions. When the record insert is synchronized insert, HighRecord insert完了以后,返回给Client,说:我成功了 But you can't search for it. Why? Because it's global. Second index Samuel update. I would say this database has been divided into DynamoDB. The global secondary index is asynchronous updated. It usually is not a minute to update it, but it still has the time to do it. If this DenimalDB performance is degraded, That's the time for you. When you insert a record, you record insert is a success. not just the global secondary index Inserted 成功, global secondary index insert 成功的话,可能它是 asynchronous 写的,这样的话, Uh, It is just a little bit, just when global secondary index is written in the same way, you can use the index to read and write. If it's not written, it's not going to read. Huh? There are people who say why not to make it synchronized. You can't change the record, but you can change the global secondary index. If you have a record, you can change the record of six nodes, and your effect is very low. This is a perfect decision. Then we have a question, "DynamoLacDB Global Secondary Index Read and Write are also Quorum? It's not Coral, because you have an index You read and write corum are different versions. You are an index, so you don't have to do corals, you don't have to do that. uh This is the case. When you read Global Secondary Index, you have to do well and prepare your data for a certain style. This style means you have a certain time. You have a certain time for a while. I'll give you a example 假设我们把刚才这个值 Thank you. and the color from red to red is black. and then red becomes black. If you read the 191, you will see the latest data. Black and Honda. But if you search, you can click Global Secondary Index search red. If this Global Second Index doesn't update the RAD, you can also read the RAD from the RAD. I can still get from the RAID. Because the global secondary index is the first to move from the RAID. And then to the black. It's two steps. Red and black are not in the cartridge. You may have a similar situation. You can read the HONDA version of the latest book "Black" And if you use red to search on it, you can search on it. If you use black to search on it, you can search on it. Because the global secondary index is the same as red and black. So this is the potential. uh But it's not a radial red quorum, the radial red quorum is too high. I think this is not a need. So, there are people who ask, "Do you read secondary index? Will there be a past-time data?" Yes, of course, there will be a past-time data. You write it, especially the global secondary index, there is still data. If you don't have Steal Data, you must use Cross-Chart Transaction, called Two-Face Commit. Two-phase commit, right? Two-phase commit, you know, performance is just 100. So you said you need to use 1ms, now you need to use 100ms. You need to use 10ms to 100ms, at least 100ms. from 100, that you... ...and you back to the question. Many times when you have performance, you have to handle 1/1000 of the things that you have to handle.
[40:00] 不handle的就是没必要你不是证明一个数学公式啊做工程的时候做共产不是这么一个数学公式,如果它出现的概率是一千万分之一,是不handle的,你尤其不会把牺牲efficiency去handle这个事情,你是不会做这个事情的。所以你读 Global Secondary Index 社会过时的数据好这个Global和这个Local和这个Global Secondary Index就讲完了,大家有什么额外的问题吗?谢谢大家然后这块很多想法就是很多设计理念和观点的就是和学术界是不一样的就是嗯因为工业界和学术界是有很大的不同的,像学术界里面特别喜欢Haskell这种语言,我当时学Programming Language的时候特别喜欢用Haskell,是吧,OKMOL这种语言,但是工业界除了Gentstreet用OKMOL,Gentstreet是六七百人的一个公司用OKMOL以外,是没有人用的,这个是没有人用的,然后虽然这个Functional Language是非常好的一个概念,这个Okemo Haskell写过来非常好的概念,但是它确实没有人用。就是工业界的学术界不一样。然后学术界的话比较喜欢考虑一些 corner case,但工业界很多时候 performance 是远大于 corner case好然后我最后一个问题说是用secondary index读数据, 岂不是要读两次?如果你这个 partition 不在一个地方的话 你是要读两次很多时候也看你这个读的时候你就要读什么了你如果只是读ID的话,你就一次读完了,从partition里面读ID一次又读完了。但如果你是要读record的话,你要enrich这个record的话,你是要读两次。这个和这个SQL是一样的,SQL做enrichment的时候很多时候一个record要读好几次,这是正常的,这个performance不会很糟糕的好然后我们再来看这个rebalance partitionRebalance Partition 在database 里面你很多时候要Rebalance Partition 为什么呢? 一个是一方面原因是Steel 原因一方面原因是费力原因然后从skill的角度来讲有两种Skill,一种是QPS,你的QPS过高的话,你可能需要更多的CPU去处理,那你需要加新的Partition另一种Skill是从Data角度来讲如果你datasets太多的话,你可能需要加新的partition,那从加新的partition,你有更多的disk和memory去存储它。是吧从skill的时候我们就可以想一下以后问的时候 skill 也是有两种 skill 是吧 一种 skill 是 QPSQPS可以加更多CPU来解决,一种Skill是Data,Data可以加更多Disk和Memory来处理。还有一种原因是,你说的Node都是Commercial Node,其实不是Commercial,就是说的Node叫Chief Commercial Node,它比较便宜,它会Fill。并且Fill的概率不是太低是吧如果你知道那个birthday paradox的话就知道在一个大的Data Center你基本上每一秒钟都有机器会Fill每一秒钟都有机器会Fill所以当一个机器fill的时候,你需要用其他机器来代替它,take over 它的 responsibility所以这种情况下也是要repartition所以不管是skill的原因还是fillure的原因,你都需要把data从一个node到1移到另一个node,然后他把这个过程叫rebalancing,就是partition rebalancing所以说这个Pretitioner Balancing的话需要有一些东西你要满足,就是有一些Requirements,就是你设计的时候相当于有一些Requirements要满足。在rebalancing 之后,你相对来说你的data是比较even and distributed 是吧?这个是很重要的,因为你如果是skill的原因,data size 不够的话,你不能balance 以后所有data在一个node上,另一个data是空空如也的这个不是一个合理的设计然后在rebalancing发生的时候,你的database still should be available,就是你database还是可以接受read和write的,这个也是要支持的,就是你不能rebalance,你自己做rebalance,然后就service就响应了,这个是不可以的。其次的话,就是你不需要移动,就是,more than necessary data,啊,你不需要移动more than necessary data 去rebalance,比如说,啊,你比如说你是久不弄的,你加了一个新的node,那你最多需要移动1/9的数据是吧,或者是1/10的数据。你不能说你先加了一个node,然后所有的data全部移动了一遍,那这样是非常不Efficient的。因为这个里面 在 Data Center 里面 在 Database 里面Database和Datacenter 里面,Network是最宝贵的资源,就是所有的资源里面,Network是最宝贵的资源。就是在这个我们可以想一下说资源里面有什么资源,CPU非常不值钱,memory相对还可以吧,看什么你要做spark了,memory比较值钱
[45:00] 有时候你如果是 data intensive memory 就那么回事儿disk是非常非常不值钱的 CPU, memory, disk,还有什么network, network是非常非常值钱的Network 是最值钱的资源 是吧如果让我排序的话 当然就有一些主观考虑Network 是最值钱的,然后其次可能是memory,然后其次是CPU,最不值钱是disk,所以是你希望是以后当你做这个 partition rebalance 的时候当你做partition rebalance 的时候谢谢大家你不希望move unnecessary data, 因为你move unnecessary data, 换就有 extra cost on the network, 是吧?所以Network是最保隔期的。Network是资源什么?就是Socket,就是NetworkSocket,就是当你把资源从,当你把资源从,当你把资源从NodeA,Transfer到NodeB的时候,你要占用的这个就是带宽Banbase你是要再用 socket 是吧?你是要去再用 bandwidth 去传输这个资源,这个资源是最宝贵的怎么样做partition,我们现在不说怎么对的,先说怎么样做repartition是错的怎么样做这partition错的呢?是根据你partition的数量磨一个数比如说你是十个partition就磨十那你data比如说是1ID是1你就在partition1上ID12就在partition2上这个做法是绝对错的为什么这个做法是绝对错的呢是因为当你的partition 如果你是每次层2 层4还好说在你partation数量如果从10变成9了或者从9变成10了你所有的data全部要摸一遍你可以想一下你比如说之前是磨9的话,9和10是互制的嘛,这个9和10是互制的,所以基本上所有data全部要录一遍。就是多少要摸一遍啊就不考虑这个Number Series的事了,就是9个事故,当你increase的时候,你所有的这个data,特别是你超过多少以后,基本上全部要目一遍。你比如说超过久以后,你全部要募一遍。这个是做法是绝对错的,因为你要募data on necessary data,You move the data on the repartition and move data more than necessary.这个是绝对错的所以如果我们看正确的partition的方式的话,它有什么呢?就是首先你固定fixed number of partitions这个常做的是 React, Elasticsearch, Votemole, Uber的SchemelessUber Stimulus 相对来说,我觉得大家在Uber工作的话比较熟的,它实际上把它分成了4096分。所以你所有的data就是你上来的时候就这个schemeless这个database就4096个partition然后,因为这个可能开始的时候,这个read和read的load没有那么大,是吧?所以4096个,可能它只有一千个node,是吧?每个node上放四个partition就可以了。这块每一个partition都是一个独立的MySQL Database基本上每一个partition就是独立的MySQL database所以4096个partition你可以认为是有4096个MySQL Database Instance Serum好 这种情况下的话这个node的数量是变化在partition数量是不变的比如说这种情况下,就举了一个例子是,当你把这个cluster从四个node变成五个node的时候,你实际上是把其中的四个Node中,就是四个Node,每个Node有五个partition,其中的一个partition,引到新加的Node上。所以很多时候它剩下的四个没有变,只有其中的一个排队神到了新加弄的时候然后这样的话进行了re-partition这个是这个的话因为你这个每个partition是一个MySQL database instance 吧你当你到了一个新的node上的时候你这种情况下比如说你share的resource比较少当你到新的上面share的resource比较多了就可以做一些这个你可以增加这个可以处理更多的datasize 是吧或者是增加了一个新的CPU来帮你处理QPS 是吧所以这是 partition 的一种方式这个方式有一个难点是什么呢?就是你必须对你的 use case 才理解Uber 如果我们看那个Stimulus当时的block的时候他实际上对于所有的traffic 是有非常大的、非常深的一个理解的就是他知道他traffic增长多少,他知道他data size增长多少他arguese说我把它变成4096个partition是足够20年甚至30年的使用的,就是20年30年有就是是足够使用的是吧,就是所以一上来就设计成4096并且他对它对于这个就是用Schemless,40096个partition,一开始的utilization rate它也是有估计的,是吧?那比如说一开始的时候,它知道每个partition里面大概平均下来有200MB data,是吧?或者是一个Gigabyte data,它大概有个平均估计的。他知道自己一开始会在什么状态然后在十年后会在什么状态所以他估计这次
[50:00] with no partition. is good. But this is often You have no pre-knowledge. For example, you are setting partition database for Amazon. For example, you are setting a Amazon RDS, which is Amazon Relational Database. You don't know your client will have a request You don't know how to use your database So you can't consider QPS and data size In this situation You can't do the partition of the number of the number and control If you have a partition number over high, for example, you have 100 partition, you have 100,000 partition, That every partition is a MySQL instance, it's overhead is very high. because it has a million partitions, a million MySQL instances. But if you need 100% of the party, you only need 10% of the party. You need to cut the partitions in the future. Of course, this is also possible, but it's very difficult. From an engineer's perspective, you need to take a month or two months to fix it. tracing a partition number just right. It is to be able to do your use case and business to be able to do it. This is the limitation. Thank you. And the other partitions is dynamic partitions. This dynamic partitions, if you had a data structure called AVL trade, or we talked about B trade, When you do B-trade, this is a lot of similar features of AVL-tree and B-trade. In the database of B-trade and in the data structure of AVL-tree, it has a lot of similar features. So When you start partitioning, you can only do one partition. But for the database, you can set up a 3, 5, 10. It's about 10 partitioning. But if we don't do some optimization, we have a partition. And the partner will grow and grow and grow. Then when you need to go over a threshold, like 10 gigabytes, in HBase, it's used to be a threshold. When it's over the threshold, it will be divided into two partitions. And it will be divided into five parts of the data. It's like AVLTRI or Btree. It's like AVLTRI or Btree. It's a bit like AVLTRI. It's a dynamic partition. It's a bit like AVLTRI or Btree. It's a dynamic partition. It's a bit like AVLTRI. Key Range is a little like Segmentary. If you're learning your sharenui visa I'm going to add There is a segment tree called Segment, which is very suitable for a I think it's a good thing to do. It's a good thing to do. It's a good thing to do. It's a good thing to do. This is So you can use the key range partition as a segment tree. So this is a dynamic partition. It is a dynamic partition. It is a particular particular part. But it is a particular part. is also possible to fix it. This is also possible to fix it. We have a question about why you need several parts of the heat. Because you set up a database, you have to put a lot of data in the system. Partition is to bring production database back to the production database. If you go to the partition, you have a partition. The data is a half, the data is a half, the data is a half, and it starts to do partition. that performance is not very bad. So, when you start to start the initial request, you will have to go back to the initial request. If you have 10 parts, you can just take 10 parts That way, the data will not need to do the repartition. The effect will be higher. Okay. Thank you. Thank you. This is the dynamic partition, a little like AVL trade or Btrade partition. The last partitions are called Cassandra, or the other one is called Katma. I don't know what it means. I don't know what it means. Cassandra is what is called? It is called number of nodes. The partition of the number is proportional to number of nodes. For example, if you have a node, you have 3 partitions. If you have 1000 nodes, you have 3000 partitions. This is also a way to do it. When you add a node, for example, you have 100 nodes You add a node You may be able to do this 100 partitions in the partitions. 早见其中的几个partition 把它split一下 然后把那个
[55:00] 找这三个partition把它split一下,然后把这三个partition split的partition放到新的node里面这也是一种方式,就是这个partition数量是proportional to known number这是一种方式好Partition 这块说完的话,这时候要说一个DevOps 相关的,也是经验的一部分。当你做这个Balance的时候,Automatic Balance和Rebalance的时候,你想做全自动的还是全手动的,还是中间的一种折衷像这个 Kafka 是做全自动的 Automatic Balancing 和 Rebalance 的所以它会有那种 Rebalance Stop 你可以search 一下 Rebalance Stop 什么意思呢比如说你的Covca topic因为卡夫特的topic是user topic 是吧?然后你当前有三个partition你上线有三个partition其中有个partition网络不太好他经常动不动的就连不上了比如说三秒钟连不上然后过一分钟后连上了三秒钟连不上过一分钟就连上了这是非常常见的你Network就连接不好是吧你三秒钟连不上然后过一分钟又连上了那这种情况下当它连不上的时候那其他Node就认为这个这个 partition 带掉了那它死掉了以后呢,它必须必须把它的 record 啊就是rebalance到另外两个nodes上然后结果过一分钟又连上了,那你因为他就活蹦乱跳伙的,是吧?那他必须把那两个record再rebalance到他上面。他就不停的重复这个balance和rebalance的过程,叫rebalance storm。这个在kafka conference上是在backend的讨论,就是kafka conference,去年参加的kafka conference上是讨论最多的一个copy。就是这个rebalance到他们做了很多优化去优化这个rebalance down,因为这个automatically的话,就是你很常见的一分钟突然disconnect,然后再connect,disconnect,然后connect,然后整个CAPA系统的performance就直接倒掉了因为你 show the backend resource, show the background resource基本上一直在做 partition 和 repartition 其次的话, repartition 这部分会占用最宝贵的 network 资源,是吧?所以说你这个 performance 是直接很惨的那死亨菜呢这是这个automatic rebalance 的不好的一点但是有的是完全做成这个manually rebalance的话也很糟糕就是你想你系统可能如果你的 data elastic很大的话,就是这个弹性很大的话你不停的就几秒钟就有人告诉你说要不要rebalance 这个效率也很糟糕所以这个是有一个取道符也有的System是作为这个就是着重方案比较简单的可能就有automatic rebalance,但是比较困难的可能就manual rebalance。你要是这种机器它不停的一会儿disconnect,一会儿connect的话,它可能就需要人为的干预了。否则的话他就不停的balance or rebalance 什么都处理不了了谢谢大家Balance和Rebalance 这块就讲完了,最后一个topic就是Service Discovery,我们在这个Balance和Rebalance这块,就是Rebalance Partition 这块有什么额外的问题呢?谢谢大家谢谢大家谢谢大家没有的话我们就到最后一个,这也是最后一个sector,就是service discovery。我们想一下,我们现在是一个User Table,分在三个Node上,拿这个例子举例,你是User Table,现在是三个Node上,所以你User Table,任何一个User Record,能在三个Node中的任何一个,是吧?那我怎么知道,比如说Scot的这个User Record 在哪一个Node上那么你必须有一个component必须有一个component,需要这个pre-knowledge,知道scot的这个record在哪一个node上所以我们这个有更broder的这个problem叫service discovery,在这个micro service里也很常见比如说我现在做一个Micro Service我要靠 user service, motivate user profile,那我怎么知道哪个 node 是哪一个Node的哪一个POD number是User Service 是吧我得首先知道是哪个node,然后再知道它ponum去访问它是吧其次的话,它可能user service 有几百个node,我怎么知道我要去哪个node?是吧?这是一个service discovery 过程,service discovery 和 load balancing 的一个问题。所以常见的呢有三种做法,我觉得好像也是唯一的三种做法一种做法是所有的node是知道其他node的存在的也就是说这个knowledge就是这一层这层 knowledge 是在每个
[60:00] 每个partition 字里面,就是每个node是知道其他 Node 在哪所以它这样的话比如说我说去get-那Node0就知道这个负在Node2上另一种是加一个额外的Layer叫routingLayer那这种情况下呢就是routing layer 知道你在哪里所以你去你去比如说Gate node2的话,周庭那样就到Node2上,Gate2了这是这样的做法第三种做法就是Client就有这个Sever KnowledgeClient自己就知道这个node在哪儿,我们也把这个叫FightClient,然后Client直接就到node2上是吧这三种做法各个的好处这三种做法各个的好处我们先点评一下,这种一的做法很多时候,如果我们看peer-to-peer system的话,这就有点像这个这个 consistent hashingEASY很像Consistent HASHING,就是PEER-TO-PEER SYSTEM它是合什么?就是它没有 centralized knowledge,它是合了 knowledge,它其实还是要一个Centerlizer,但是它说的Node,它不仅帮你Lookup同时也帮你处理service 这个是P2E的做法TR的做法是你实际上routing layer就是routingTR是一个单独的module那你这个routing tier就不和这个node争夺这个lookup资源了QPS就不和routing layer就不和node争夺这个资源了如果你用tier1的话,你这个node其实你lookup和这个service是要相互争夺资源的同一个同一个机器们相互增多资源但你用第二个方式的话就不相互增多资源了你roting是roting,你这个node是node,你两个可以单独的进行skill,单独的进行优化然后用T23的这个Lentense是最好的DynamoDB那篇paper里面写过它当时是有三种做法一种是只用T23一种是T22TR3的Lookup时间是TR2的二分之一也非常简单 因为这个TR相当于是两个request这个 tier 3 是直接 request 的嘛,所以这个 tier 3 的这个 latency 是 tier 2 的二分之一,所以这 tier 3从performance的角度来讲是最好的但是这个TRS有个问题这个client 你是知道所有的server node在哪儿所以这个client其实不是普通的user这个Client是你Data Center里面那个Service我重复一下,这个Client不是普通的User,不是Consumer,这个Client是你的Data Center里面另一个Service。因为你有data在哪一个node的knowledge你如果让其他人知道的话,这其实是Security Loophole,就可以攻击了是吧就可以hack他 Twitter account所以这个Client不是普通的User,这Client是VetaCenter 里面其他Service比如说这个可能是这个node可能是server user node这个Client可能是比如说Payment Service 是吧去的Login Service,所以它不是一个普通的Service,并且第一点,这个Client不能是任何一个Client,必须是Internal Client然后第二点这个Client data是必须不停的updated的,就是你实际上这个,如果这个更新很快的话,这个Client很,可能的时候他就,Auto-sync了 就是它的数据就过时了那你不需要不停的去更新它,保证它对它永远insync的所以他需要额外的cost,让client data 阴性不能 auto-think好,这里面就是拿其中的一种做法就是说,拿单独的routing layer解释了它在电纳生产里面什么实践的是吧在Data Center里面,比如说拿这个Look Aside,或者是Routing Layer,额外Routing Layer,这个Rooting Learning Knowledge其实是从Rootkeeper或者是ETCD里面读到的,它是有个从一个Global Configuration Service这里面是拿Rootkeeper做这个Global Configuration Service,然后从这里面读到的,所以它永远有最新的最新的没有任何问题的这个routing information所以这个Rootkeeper是保留什么呢Rulekeeper 是保留从 k-range 到 partition 然后从 partition 到 node 这个信息的从K range 到 partition,K range 和 partition 是怎样 map 的?当然K range 和 partition 这个 map 也有可能会变,是吧? 如果你比如说这个 partition 不是不是一上来赛的好的话,Clear and Partition 这个关系是有可能改变的然后从partition到node的信息也是不停的会变的,这也是为什么要the service discovery to 12
[65:00] 所以这个rootcaper是保留从k-range到node之间的这个knowledge的如果我们分细分开的话,就是这种减任的partition,我们见到没见过。谢谢大家我们细分开的话就是从 k-range 到 partition 和从 partition 到 node 。这个信息的然后这个是用ROOKEIPER存的。这里面还有另一个信息是从Node叫IP-address,因为这个Node的IP-address不像这个partition和这个QRange变化这么快,所以它经常的话这个IP-address是用DNS来处理的,Domain Name Service。超越了好所以就是这个就是service discovery,就是它实际上它sauce-to-choose是rootkeeper,用rootkeeper来作为sauce-to-choose,然后这个不管是这个routine knowledge全部去rootkeeper上来进行update,然后这个node down掉以后,它也更新入kaper,然后入kaper知道它最新的node在什么地方然后 Kubernetes 也是提供 Service Discovery 功能的,因为 Kubernetes库姆乃茨 我记得好像前两天跟大家分享 请你分享一个文章 库姆乃茨其实在ETCD上包装了一层 wrapper 它其实是它用 et/cd 然后增加了一些其他的 functionality所以它这个底下还是用ETCD的,ETCD是Rootkeeper的另一种,也是一种Consensus Service是RuleCaper的一种直接的替代品好,这就全部讲完了,今天主要讲的是partition讲了 partition 就是 partition k 怎么显示吧然后有多种 partition k 的显示方式,有 range k 有 hash k然后还有 composite case,或是 compound case,然后其次的话讲了Secondary Index, Global Secondary Index, Local Secondary Index然后呢,然后又讲了这个repartition这一部分,怎么样做repartition是对的,怎么样做repartition是错的基本上大家刚开始自己设计的话都会把reparation设计错,就是常见的错误。然后最后的话讲service discovery讲了四个大的方面,关于partition这部分有什么问题吗?如果有问题的话回答一下,如果没有的话,今天就到这里好了。谢谢第一种routing的方法是用gossip来实现的没有必要用Gossip实现如果是peer to peer的话你可以用Gossip来实现否则的话你这个node可以直接跟do paper来talk你弄的比如说我给你举个例子node说我要找foo,然后我去node2上说foo在不在那里,那在的话就request成功了是吧然后如果不在的话,Node2返回Node0说,如果不在我这里了,你是不是需要更新一下你的这个 knowledge那漏的零直接去入Cabular上,更加knowledge就可以了,没必要用GallSafe时间。谢谢大家高系统当然也可以使用,但是你的data convergence 就会慢一点,就是你data怎么样就是convert到最新的data会慢一点你用Rookable的话可能很快就convert了有什么问题的话也可以直接问啊直接说一下谢谢大家好 那就这样吧谢谢大家今天就到这里谢谢大家好