```mermaid
flowchart TD
accTitle: Scalable File Distribution Overview
accDescr: High level architecture using ZooKeeper for coordination and BitTorrent for peer-to-peer distribution.
在数据写入和版本演进的设计上,系统必须严格防范写放大(Write Amplification)问题。由于目标是向 10,000 个节点复制数据,如果在 Master File 上频繁地执行微小更新(例如每写入几个字节就全网广播),这个写操作就会被成倍放大一万倍("你是 proportional to number of nodes 的,每一个 byte 实际上都被增强了 1 万倍")。因此,Master 绝对不能被无休止地频繁写入,必须采用批处理(Batch)或小批次(Mini-batch)方案,在固定时间段或积累到一定大小阈值后再做同步。
为了保证高可用与防范单点故障(Single Point of Failure),写链路的流程规范如下:
1. **复制写保证**:主节点侧维持一组小型机器集群(Small Group Machines)。当写入请求到达时,必须成功写完组内所有副本机器后,才能向客户端返回成功(Return Success to Requester);如果业务场景允许特定程度的数据丢失,才可以降级为单机写入。
2. **变更日志追加(Append Only)**:所有新的写操作都被以增量追加的形式写入一个临时的 Append File(例如命名为 `File_v12345` 的当前未发布版本),不修改已发布的基准文件。
3. **全序广播(Total Broadcast Order)**:日志在副本间复制时必须满足全序广播,确保所有副本节点接收到的变更顺序与 Master 完全一致。讲者在此提醒了一个数据库领域的经典暗坑(Catch):单纯保证变更命令的全序到达,并不等于数据完全一致。例如,如果日志里记录的是非确定性函数调用 `NOW()`,不同节点执行时的机器时钟不一致就会导致数据分叉;正确的做法是 Master 节点先将时间函数求值为确定性数值(如把 `NOW()` 转成明确的 `6点15分`),再将具体数值广播给所有 Replica。
```mermaid
flowchart LR
accTitle: Append-Merge-Upload Workflow
accDescr: The step by step lifecycle of a file version update from writes to ZooKeeper registration.
W["写请求 Writes"] --> A["追加至当前增量<br/>Append Log (vNext)"]
A --> T{"达到阈值?<br/>(时间/大小/条数)"}
T -- 是 --> M["本地 Merge<br/>旧基准文件 + 增量日志"]
M --> U["Master 上传合并后大文件<br/>至 Amazon S3"]
U --> R["递增并在 ZooKeeper 注册<br/>Pump Version"]
T -- 否 --> A
```
为了彻底解放抢票时的写性能,数据库应采用快照隔离级别(Snapshot Isolation),主流的 MySQL 和 PostgreSQL 均天然支持此配置。快照隔离的核心优势在于“读写互不阻塞”(Readers do not block writers, and writers do not block readers)。当事务 T1、T2、T3 陆续发生时,读事务读取的是与其开启时间戳对应的历史快照数据。虽然此时用户查询到的余票数字可能是稍有延迟的旧数据(Stale Data),但在秒杀抢票场景下,终端用户完全能够理解并接受短延时的数据状态,关键在于系统保证读不会返回脏数据,同时海量只读请求绝不会拖慢抢购写入。
```mermaid
flowchart TD
accTitle: High Concurrency Booking Flow
accDescr: Diagram illustrating how concurrent user booking requests are converted into an append-only log and processed asynchronously by background batch and allocation servers.
Uber 的服务发现采用了类似 Smart Client(肥客户端)的设计思想。每个 Client 端在本地维护了一张路由映射表(Mapping),发请求时并不直接穿透昂贵的外置代理,而是先在本地进行端口转发或查找。例如要调用 Service A,客户端直接把请求发送到对应的本地虚拟端口(如 Port 12345),再由底层的路由映射表查出该端口对应哪台机器的真实 IP 和 Port,进而直接建立连接。如果目标节点不可用,客户端再去尝试本地缓存的下一个可用节点。当本地映射彻底失效(outdated)时,客户端便会向集群的全局配置中心 ZooKeeper 请求拉取最新的服务 IP 与端口列表。通过这种方式,Uber 内部专有的路由组件(如 Martin 等)与 ZooKeeper 配合,实现了轻量级、高可用的去中心化路由与状态维护。
```mermaid
flowchart TD
accTitle: Client-Side Routing and Lookup Architecture
accDescr: Flow diagram showing how client requests are verified via RTAPI, resolved through local mapping, and updated via ZooKeeper.
## Notable quotes
> [05:00](https://www.youtube.com/watch?v=FI8G3VeI94w&t=300s) 你是 proportional to number of nodes 的,每一个 byte 实际上都被增强了 1 万倍 — Scott Shi
> [10:00](https://www.youtube.com/watch?v=FI8G3VeI94w&t=600s) This is not customer facing, it's a data center... So this problem doesn't exist — Scott Shi
> [20:00](https://www.youtube.com/watch?v=FI8G3VeI94w&t=1200s) 比如我和景祥同时看这个座位 A 有没有人,我们两个事务看的时候都发现没人,然后我去订、景祥也去订,如果系统给两个人都返回成功,那就出现了典型的冲突。 — Scott Shi
> [33:00](https://www.youtube.com/watch?v=FI8G3VeI94w&t=1980s) Readers do not block writers, and writers do not block readers — Scott Shi
> [36:00](https://www.youtube.com/watch?v=FI8G3VeI94w&t=2160s) 已有的 12306 Rate Limiting 好像做的不太好,我看到好多程序员可以写脚本非常快地抢票;如果能用程序抢票,肯定它的 rate limit 没有做好。 — Scott Shi
> [01:05:00](https://www.youtube.com/watch?v=FI8G3VeI94w&t=3900s) 在用户购票状态尚未确认为 booked 之前,系统是完全允许丢失数据的(lost data)。 — Scott Shi
> [01:10:00](https://www.youtube.com/watch?v=FI8G3VeI94w&t=4200s) 一个就20多万 — Scott Shi
> [01:14:48](https://www.youtube.com/watch?v=FI8G3VeI94w&t=4488s) Service is not available
[5:00] Scott Shi: 你是 proportional to number of nodes 的,每一个 byte 实际上都被增强了 1 万倍
[10:00] Scott Shi: This is not customer facing, it's a data center... So this problem doesn't exist
[20:00] Scott Shi: 比如我和景祥同时看这个座位 A 有没有人,我们两个事务看的时候都发现没人,然后我去订、景祥也去订,如果系统给两个人都返回成功,那就出现了典型的冲突。
[33:00] Scott Shi: Readers do not block writers, and writers do not block readers
[36:00] Scott Shi: 已有的 12306 Rate Limiting 好像做的不太好,我看到好多程序员可以写脚本非常快地抢票;如果能用程序抢票,肯定它的 rate limit 没有做好。
[65:00] Scott Shi: 在用户购票状态尚未确认为 booked 之前,系统是完全允许丢失数据的(lost data)。
[70:00] Scott Shi: 一个就20多万
[74:48] Service is not available
Original transcript
[0:00] 好,我们今天开始聊两个就是之前在群里面讨论过的Design。第一个Design就可以认为是Scalable File Distribution System。嗯这个其实还是有挺多use case的,我记得王小豪同学也在那个群里面说了一个就是有一个design的问题这个很像他当时问的问题是怎么样就是build a continuous code deployment system,然后这个code compile 以后可能很大,可能10GB然后你需要每天可能要上千个Deploy然后你要做的就是把这个code compile然后link compile,然后compile完了以后把这个code push out上千个那个server上,然后他是每天都在就是automatically做的。这个的话其实和这个很像,他那个设计我也是借鉴了一下那个设计吧。然后这块的话这个问题也是类似的,就是你有一个multi-region,multi-zone data center。然后你需要一个不停的记录一个就是你需要不停的 replicate 一个 changed file然后这个file呢可能是大概10GB,然后你需要去crow到比如说100sign nodes,或者10sign nodes,然后每个nodes可能会go down并且不能有任何 data loss 然后应该怎么设计然后我想了一些solution,然后借鉴了一下,也是借鉴了一下那个就是他当时YouTube的视频里面那个engineer solution核心思想就是用Rulekeeper来keep一些configuration,比如说你的location or masterfile在哪里。然后你的这个MasterFile的VersionChange在哪里,就是是什么样子的。然后你MembershipManagement,SharingGroup也可以。这个MembershipManagement,这个就本来就是ZooKipper做的,ZooKipper是专门做MembershipManagement的。因为它中间有一些Consensus,比如说哪一些,有一些Consensus是比较重要的。比如说哪个Member是退出Group了,哪些Member是在Group里面,这个Consensus是比较重要。还有的话就是transfer的时候是用bTorrent或者是 peer-to-peer network transfer large file 的。我这块由于时间限制,我没有对 peer-to-peer network 进行深入的谣解。然后大概就是有个种子,有个Seed Group Management,然后每个的话就是我看他Seed group有个limitation是大概有2000所以如果你这个Seed过多的话,那剩下的可能只是download的,可能就不upload了,还是可能有个这样的限制。我这块没有了解太多,我只是简单读了一下这个就是写的时候的configuration,然后有可能可以用 BitTorrent 去管这个Membership 因为这个 BitTorrent 设计的时候就是 peer-to-peer network 他就assume 这个Members 可以 join 然后 exit frequently所以你可能也能用 peer to peer network 去管理 membership可能也是够用的但是这样的话你还是要有一些还是要有一些那个,还是要有需要有一些啊就是管一些比如说你一开始的时候他是有一个address能找见这个peergroup在哪里应该有这种,之前有一些比较老的设计有什么super user,butolerant好像比那个稍微先进一点。所以我不是很清楚他具体怎么设计的,但是已有了这个设计应该是能满足这个要求的。谢谢大家谢谢大家好,大家有对Bittorrent比较了解的share一下knowledge吗?有人说加不进来这个room meeting谢谢大家好吧,那我看到还有人的交流,应该没问题,我们接着聊这个。所以这块的话,首先就是设计思想就是用这个Rulekeeper加上这个Bitorrent来分享File。Bitorrent分享File的主要原因是不想就是havveload一个Node,比如说你如果只有一个Node去这个,去share resource的话,你用node copy events,node network就被卡死了。一般来说,特别是如果你要copy,node要copy到另一个node,另一个node是在另一个datacenter里面,你要再用最宝贵的,就是inter data center network,这个是最宝贵的,一般的datacenter里面最宝贵的资源,所以这个一般是不,就是除非你有很好,一般来说你是想avoid,
[5:00] 这个resource占用的所以说 我这块想的想法就是 首先Master File的话不应该change too frequently这个MasterCell不应该change too frequently那么否则的话你的read amplification就是你这块写一遍然后你replicate 要replicate一万遍你是 proportional to number of nodes 的所以说如果你每一个byte都update的话,你实际上每个byte都被增强了1万倍所以这块这个MasterFile不应该去写更多所以你可能需要一个是那种batch,mini batch,或者是这种看一个固定的时间段来做的,这是一个想法其次的话这个File的话,在一开始写的时候,在MasterFile就有一个,应该有一个single point failure,防止有single point failure,所以应该就replicate,但如果你说MasterFile可以丢失的话,那其实就不需要replicate然后再其次的话,你在append这个change的时候,就比如说你现在file是在有ABCD,你append的EFD的时候,你这个不应该有data loss的。然后最后的话是如果你 read from replica 的话,你可能会读到 still data,但是不应该有 corrupted data,就是你如果从 replica 读的话,你可能需要一些过时的 data,不应该有 replicate data这块想法的flow也是比较straightforward的首先有一个small group machine,这块是主要做replicate,如果你没有replicate的需求,就是它允许certain degree or data loss的话,你就一个也可以。然后你这个machine是keep to up to date version of files,然后Each of the write,就是你比如说我现在有个write request,我要写这个file,有个write request,我必须write到所有的machine然后才能说 return success to requester如果只 write 其中一个或两个的话,我不能 return success to requester然后 new write 是 append到 change logs 的,比如说你现在这个file name 可能是current version然后你现在在append的这个version 还没有publish version 可以叫new version number 我们可以叫做 version 12345那么当你replicate的时候,这个write order,replicate order是total broadcast orderTotal Broadcast Order就是首先没有Write Loss就是你没有Write Loss,你没有Loss of Data,其次的话Order Replica得到那个change是exactly the same order as the master node.就是Total Broadcast Order,就是说它是一种replication的一个,就是一种order,说明什么呢?你所有的replica拿到的data和master上拿到的data应该是一致的但是这块有个catch是什么呢?因为在database里面,这是个file,就是说写的都是string了就无所谓了但是在database里面即使你guarantee total broadcast order,你data可能还是不一致,因为你在database里面你可能比如说靠的是timelow,那你在这块这个master machine的timelow和replica的timelow就不一致是吧,那你这种情况下的话,你这个master machine的靠timelow的时候可能要把这个就是这种function转化成具体的数值,比如说你在master上写timelow的时候,首先把timelow转化成6点15分,然后你replicate的时候你replicate6点15分,而不是你说你replicate的时候,你replicate6点15分,而不是你说你replicate的时候,你也可以说replicate time now,那你这样的话在master在那个replica上的timestamp最后只是不一致的但是最后的话,如果没有data loss的话,允许data loss的话,可以不做replication。然后我们看到这个新的request呢,其实是不停的append到这个file的上面的。是不停的append到file的这个,比如说fileA12345上的,然后当你的certain threshold到达的时候,比如说你是过了一段时间了,或者是你这个write已经超过某个数量,或者是你这个size到达每个数量,你可以pump version了。那么你新加的append file,就是你首先新建一个新的append file,就是version+1。那这样的话所有的新的request write request要写到这个version+1这个上面然后就是之前那个version比如说现在新的version是124那123这个version和之前的file就merge起来了你就把那个file就是123D version和这个incremental update和这个旧的file merge 起来然后当你merge起来以后,你可以用这个master node,只用master node来upload,把这个uploaded merge file呢,to Amazon Street,我们说过M1 Street是object storage,你可以认为是dakabase,也会叫object storage这些,然后当这个file upload成功的时候,你就去register入keeper,入keeper的话,Uber里面有个叫flipper,我不知道他是用rootkeeper,底下是用rootkeeper还是用,ETCD的 反正它肯定是用一个consensus service来实践的RuleCable上它是一个global configuration所以他
[10:00] Guarantee you, basically guarantee you. when you write it, it has linearity, You can read the book you can read the book you can read. uh, You will read the most of the first time, it is a global configuration service. But when you use rulekeeper, you should be careful. Rulekeeper expected use case is you don't write too often. Because every time rulekeeper is going to be a... Leader election, I saw Uber said that the stimulus is a leader election. It's available to 200ms. This is still a bit longer. But for a long time, the leader election is a little longer. This time is quite a long time. So performance is not good. So QPS, rulekeeper expected QPS is one request per minute. If you have 100 per second, you may not be able to use rulekeeper. Rulekeeper can ensure replica The data is consistent. This is the question, how uniquely identify a file? Different users can upload the same file name, but the content is not the same. This is what you can do through application level to solve. If you file is the same, the content is the same. This is not customer facing, it's a data center. Just wrap, quite sure to copy the data by a large file to distribute it to a selected node. This is not customer facing. So this user is application code. So this problem doesn't exist. The design of the design is Master node, and then Upload the file to the S3. And when it was done, when it was done, it was done. The root keeper version pumped. It was pumped from the new version. It was pumped from the new version. It was pumped from the new version. It was pumped from the new version. If master is done, you can use slave file to do the same thing. Because we said before, he wrote it. Master and slave. Master is done. Master is done. Slave is done. Slave is done. If it is done, it will be done. So you slave is not lost. So you can also use slave file and then upload to S3 and then pump the rootcaper version. Rootkeeper is also tracking group membership or broadcast group. If it has a membership change, it will modify the rootkeeper. So it will keep track latest and up-to-date group members. This is the rootkeeper's main usage. It is tracking accurate group membership. as a download command. Group member is a million. So the download command of group members is using BitTorrent to share this file. There is a seeder, which is to select some to download. For example, you first download 10 people, then you will go to seed group, and then you will go to seed group, and then you will go to seed group, and then you will go to seed group, and then you will go to seed group, and then you will go to seed group. And this is the file that says that there is a file. deduplication, then use file size and hash signature to do. This file deduplication has an image deduplication, and an image DNA. This is a very simple way to use file deduplication. um Some of the images are in the safety of Facebook. I'm talking a little bit about imageDNA. Facebook is what is happening. There are many people who have published a false video, a red video, a red video, or a red video. That it must be done. If you just done this format, it can reformat. It can change, make it simple changes. It can be uploaded. It's like image DNA is the same thing, it's like from the image in the image, you can change the color, or the size of the size, and the size of the image. Then you can do the DDo. Depending on the use case, if you have a file file, you can use file signature, hash signature, or image. Then you can use image DNA to do the DDo. How? So we have some details Um, maybe,
[15:00] 要做这个project还是要去掌握的,就是去做deep dive的比如说这个 BitTorrent 我记得 BitTorrent 是有一个 magnet link 磁力连接 然后你可以通过磁力连接去你可以通过这个磁力连接去那个去download的这个就是就是加入这个这个share group,然后你可以作为leacher或者是seater,seater的话就upload的然后Literature就是download所以这块可能还需要一个process去Manager就是当这个Rulekeeper Pump新 version 需要有一个stable的process 然后去不停地去manage谁是seater 谁是seater 谁是leater 然后保证这个file distribute 过去对于任何一个reply卡来说,你可能会有同一个file在不同的version比如说你可能有file version 1,file version 2,这是download好的。然后你可能有个file CR download,就是表示它在download的过程中。那么因为你在download过程中说你会不会显示的,不会受read request的。然后这个file 1这种是old version,still version,可能就是在过一段时间后会被在这个replica上清除掉。然后这样的话保证你这个机器没有多余的file。因为是就是version最高但是没有这个没有in progress一种然后download的时候如果用过Bitcoin的话就这样他也会有个判的一个什么CR download的当他download完的时候他会把这个CR download的给remove掉就是 rename 成 File A version 3这样的话是可以满足这个需求的。我觉得这个设计是work的,但是这个bit torrent这块还有一些细节的问题。可能就是如果真的要做的话需要去研究一下这个的话,我觉得大家有什么讨论的吗?就是有什么想法吗?对于这个设计。可以直接发言如果没有什么讨论想法的话,这个设计可以用在多处的,你可以想一下你要copy一个file,快速的copy一个version的file去10k nodes的话,这个设计其实还是可以用在很多处的,比如说你这个code deployment,比如说你这个Broadcasting,其实你就是Broadcasting large file,在Data Center里Broadcasting large file嘛所以这个Rootkeeper加这个BitTorrent应该是能解决的。中间还有一些细节可能需要figure out,但是这个应该是可以解决的。特别这个BitTorrent这块,我没找见一个很好的一个Design Dock,我觉得中间还有一些细节需要解决。我们在讨论这个12306这个Ticket Booking System,这个相对我可能比较熟一点。所以我之前也想过这个问题,所以我们可能这个我不确定的相对比较小一点。然后欣妖问这块可以用刚才那个地方是可以用Multi Leader吗用 multi leaderMate Nieder如果有multi-leader的话你的file会有conflict,这块result conflict很麻烦,我觉得没必要,还是single leader 挺好的。好好,我们现在就是讨论一下这个12306的Ticket Booking System。这个问题我也想过,之前想过一段时间,但是这次讨论的时候,具体的把一些很多Solutions写下来的话,我觉得还是有一些挺有趣的地方的。就是12306是国内的一个火车订票系统,它的peak QPS是在一个million左右然后他但是他这个QPS可以grow到more than 1 million,就是可能grow到那个什么10个million,甚至更高。那么在这个里面我还加了一些额外的feature,因为我其实没有用过12306这个网站,因为我出国的时候还没有高铁,所以我没有用过12306这个网站,所以他说有一些,我想的他就是我见了一下,就是可能说您可以比如说您可以book一个tickets从CityA到CityB那可能会经过多个旅程,比如说你可以从北京到杭州,可以变成北京到Hong Kong,可以从北京到杭州。然后你book 比如说从北京到上海的那个那个那个就是从北上那条线book从北京到杭州,然后从杭州到广州你可以比如说从那个杭州到广州的线进杭州到广州,然后road3的话可能说从广州到香港,就是你其实可以把一个tripbook成几个小的阶段。然后你的客户应该也可以revoque a book at any given time,这个我觉得应该是support,应该可以支持的。然后我查了下就是大概高铁的每个set是有一千个左右的座位然后18
[20:00] 电源的traffic是33亿人18年的traffic是33亿人次Gross Rate 是 9.4 那最高的Day record 是13个million人次 per day,这个是在19年春运的时候我简单的estimate 了一下,它实际上是expect的是一天可以handle50亿人次,就是一年可以handle50亿的traffic,差不多就是能用应付大概可能10年左右差不多够的然后其次的话一天可能一天的话如果是50亿人次每年的话呢每天平均下来就是1400个Million1400万仁慈那么如果是假设85%的占坐率的话,那实际上需要一天发车是1600016500册次然后我就是这块假设的话是春运这种高峰时刻的话应该能handle多少呢?应该能handle28个million每天,28个million每天的话,用简单的QPS来算的话,就是因为现在的QPS是一个million嘛,假设它这个QPS是10个million的话,那么10个million一万辆车的话,实际上我们车数应该是高于一万辆的,10个million每天是一万辆车的话,所以它其实每辆车的人次定做的 2PS 是 1K就是他这个每辆车就是你可能一天是有10个million的QPS,就是高峰值就是10个million QPS,但你平均到每辆车上的QPS大概是1K,就平均到每个车次上,比如说从北京到上海上午12点开出发这个车的QPS大概是1K左右然后我这块设计主要想的是它这个Botonex在database上呢所以最常见的就是比如说你很多人同时就是做同事book同一辆车的时候,同一辆火车的时候,那么你很有可能有发生这种read, modify, write conflict,就比如说这read, modify, write, conflict是什么呢?比如说你在订那个theater票的时候就说,我和,比如说我和景祥同事看这个这个座位A有没有人,然后然后我们看都没有,我们这个transaction看的都没有,然后我去book然后紧想去book,然后我们都返回成功的话,那我们就出现conflict的话,就是read,modify,write,conflict这是一种常见的conflict, read, modify, write conflict是有一种常见的 concurrency control model是可以解决的就是那个 two-phase lockingtwo-phase locking是怎么解决的呢就是你的当你RAID的时候,当你进行TransactionRAID的时候,你是拿一个读锁,就是拿了一个读锁,读锁是RAID Lock是Non-Exclusive Lock然后当你write的时候你拿到是一个exclusive lock的邪手就是exclusive write lock所以当我们俩同时读的时候,我们是同时,就是我,比如说我和景祥同时在读这个座位A,那我们其实两个同时拿到了读锁,那都是non-exclusive,说我们两个可以同时读。但我们其中有一个想去站这个座位的时候,他其实就必须把这个读锁变成写锁,那我必须把这个,就是不管这个lock granularity是在这个table上,还是在这个row上,我必须把这个row或者这个table lock住。当我去尝试去lock它的时候,那我就必须,因为它是exclusive的写所,所以我这个另一个那个景祥的读,必须被我reject掉,必须被我踢出去,是吧?然后我必须把这个景祥的transaction reject掉以后,我才能就是也没有其他的读的时候,我才能拿到这个exclusive的这个写所,那我才能把这个座位站上这是 two-phase locking这样的话我是可以把这个座位占到的就是two-phase locking可以做到谢谢大家但是我们这块讨论的时候就是这个最常见的问题就是re-modify-write conflict,这是很麻烦的一个问题,这也是很多时候你看起,比如说12306很大的一个很高的QPS有时候能handle,但是你去电影院book一个tickets有时候会fuel的原因其次的话,我这块设计的时候,我想的就是relational database因为你需要 strong transaction,并且这个 strong transaction 不只是这块,还有什么需求呢?你 book tickets 的时候,你可能先占了这个座位,说先占了这个 tickets,你很快要做的是 transaction,表示你有 money 去 pay 这个座位。那这块的话肯定也是要follow up做一个就是transaction的时候肯定是要就是financial transaction 肯定要用relational database 比较好,用noSQL的话可能会有各种各样不必要的麻烦然后再其次的话这个database是一定要sharded的这个肯定很明显的这个如果你有平均到一天有10个million人QPS的话,这个database是一定要
[25:00] 一定要被sharded 10 billion QPS 的话你这个10个million QPS的话,这个是一定要被sharded的然后我们这块的话因为他这个QPS可能也没有这么多train,所以这个QPS可能还是要比这个EK要大一点可能还是要比1k大一点,我记得我有不同的,就是用不同的方式来evaluate,可能是个10k左右。这个是假设,你就是比如说一天一开始的话,就比如说开始预定明天的车次,那我明天1万辆测试同时开始预定,但是很多时候可能好像是分开预定的,所以你这个QPS可能还是要比这个EQ要大一点的,每个测试。然后计划请向问了一个问题说你如果acquire这个write lock不会被shared read lock block吗会的会的,所以你这个write lock是exclusive lock的时候,你必须把所有的read lock给踢出去,这是非常传统的就是你所有看最早的relational database都是用two-phase locking时间的,这个叫two-phase locking,包括你上database的课都是用two-phase locking时间的,这也是从上世纪70年代末到,反正到最近还在用这个two-phase locking这个是会的好然后这款Database我们要shared的,那我常见的用一个shared的key是什么呢?就是我想的对这个测词,就比如说这1234在12.30分出发作为一个测词,然后把这个作为sharedkey然后把data删着过去好Sycle里面,Two-Face Locking QPS 多少?我记得几天,下个一个数据是QPS是100K每秒,最新的Data Center里面比较好一点,这么时间是100K每秒。100k每秒锦翔说:现在database用hybrid是用Two-Face Locking+Multi-Version Concurrent ControlMarpy version concurrent control 简向你试一下我意思是说,现在其实,如果是做于Transaction Possession的DB的话他locking已经不在table本身,他已经lock down那个每一个Low上面去所以我每次更改一次Database都会在每一个Database上的Low加一个他的insert transaction id 跟他delete transaction id然后通过这个insert跟delete的全数来判断你当前的陈先生能不能看得见?所以他就不需要lock整张表格,只需要lock一个lock就好了这是MultiVersion的部分,2-phase locking就是刚才Scott说的。现在主流Database一般都是谁先拿到Lock谁赢,剩下Lock都会被abort掉。就是比如说两个层层更改同一个肉然后第一个 transitionupdate 它就会在那一行上面lock住那张表 如果下一个进来也要更改这个的话会直接被uplo掉这是为了提高那个throughput做的一个选择你说的是不是就是这种啊,比如说这个Case,比如说我去读这个balance啊就是这个transaction 12说我去先读这个balance 然后呢其次的话嗯等一下这个case怎么会上我看一下Transaction level is the transaction level.isolation, that's called isolation.这个怎么说,你这个是语欲上的一个东西哦,就是对一个,对于两个全身的更改,就是,Rate跟Rate同一个set的数据的话是用这个东西来表达的但是如果是具体到一个表格里面不同的数据的话是用我说这种方法的它其实是single row的locking是吧?嗯,ok,ok,这个不直接相关,不过我后面会简单谈一下snapshot isolation 的问题,好好的好的 谢谢Shar然后我们接着谈这块就是这个shardingKan的话我propose这个shardingKan是车次就是按车次来shard那么其次的话这个says应该是pre-determined pre-allocatedPredetermined and preallocated的原因是什么呢?一方面是有很多offline
[30:00] 比如说你还是有一些售票亭去上,并且比如说你这个从北京到上海的车次,你石家庄站也是要reserve 一部分从石家庄的车次测票的,所以你这个还是要去这个就是先分好的,就比如说你从北京到上海是1000个测座,有800个测座是从北京到上海直达,剩下200个的话,其中100个是从北京到石家庄,石家庄到上海,这种先分好的。然后其次的话好像现实生活中我看到有人在铁路局工作就是他父母在铁路局工作也说铁路局也是这么做的然后我这块这个想法呢比较简单就是我这个想法比较简单,就是把booking和 set allocation 这两个动作分开booking就表示你有没有book到你有没有book到,比如说这个是pre-located,比如说北京到上海有1000个车票北京上海有1000个车票,其中有800个是直达那从这个这个这个这个肉特里面从北京到上海这个直达的肉特里面有800个那我book的时候就很快写一个record,然后它有个sequential number,就相当于是在用sequel里面时间一个queue,如果在前800个的话,我肯定是拿到测票的,如果在后800个的话,可能会没有测票,所以这个booking就表示你有没有测票,但是你book到车票以后呢,你还需要去做SETA location,这个是为什么呢?就是因为book车票上,你可能book多个嘛,比如说你一个人book了10个那我肯定还是优先把你10个人安排到相近临近的做,并且这个allocation呢,实际想一下它只要数字不是1的话,你都有一个DP的问题。就是你都需要可能,你要optimize的话可能都是要DP的问题。所以这个现在location是分开的,就是original想法就是分开的。所以说,比如说我们做北京到上海这123412:30出发这个为例子。首先这个管理员就决定了有多少个从北京上海直达的,然后有多少个是从北京到石家庄上海到石家庄的。然后把它就写入这个database了,就是它通过一些管理的后台就把这个就写了database了,所以你可能很快的需要读,比如说你放了一个configuration db,或是放了一个in-memory db,你可能不需要不停的要读这个来check是不是到了capacity了。然后其次的话呃shard的话用车次来shard的然后这个database是用snapshot isolationsnapshot isolation就是跟我们之前说的two-phase locking不一样snapshot isolation什么的你读的可能是still data你会读snapshot isolation说白了就是你写的时候不被读给block你读的时候不被写给block当你读的时候,你可能读的是比如说你现在transaction12345,我们举个例子比如说你Transaction是T1,T2,T3,你读的时候,你可能就是当你读的时候,你可能已经T2 T3已经写好了,但是你读的这个timestamp可能读的是T1,所以你只能读到transaction1之前的,就是这个write1之前的东西。你读不到T2和T3的东西,就是你读的data可能是有点still的,但你不会读一个wrong data,同时你写的时候你是不被读。给lock的 不像2-face lock的 你不会被读给block掉所以它这块可以用snapshot isolation来做这个然后MySQL和Postgres都有snapshot isolation就是你可以configure你database来做snapshot isolation然后这个proposed data schema是什么呢?就是首先有个Ultra incremental ID这个AlterIncreate的ID说白了是一个Visualize的一个Q,就是你实际上把这个作为Q的功能,谁的指晓,谁就最后先抢到票,是一个满足Q的Functionality。然后有个UID,这个UID是用车次来hash的,这个UID是为什么有呢?你当前有一个million的request来booking system你需要很快的找见在哪个database是存你这个booking的,所以用hashableUID呢能很快的allocate在哪个database上如果每个车次抢的人也很多的话你可能要把每个车次还得break出来,你比如说每个车次分成3到4节,平均分成3到4节,也可能要这么做,也可能需要这么做。那这样的话就可能就是hash车次再加后面再加一个数,比如说等分的话,4等分的话就加个1234。然后呢你有就是有一些train number啊 start time啊然后就是user 比如说我是user12345就可能拿身份证来做user然后我book了多少个tickets,我有个request UOID,因为你这个设计中,你知道你拿到车票是需要时间的,需要去系统来看到你是不是在前段。你写了
[35:00] 的时候你其实不知道自己拿不到哪测调其次你拿到测票的座位在哪,是另一个process处理的,所以这个需要有个request uid当你request的时候,你会不停的po request UID,然后知道你到底有没有拿了测票。然后最后这块是个rote,rote的话比如说用A1,A1就表示北京到上海,B2就表示石家庄到上海这种加个timestamp,然后再加个state。这个state的话,我这块想的是比较简单,就是三种情况: empty,book和cancel的AMTEK可能有两种情况,一种就是系统还没有决定你有没有分配测票另一种情况可能就是你在一个waiting list里面,就是你前面有够100个人了,但是你不到waiting list之外,waiting list number是可以configured的。然后这个booking table需要index上passengerID,requestID,root和primarykey这个PrimaryKey自己有代index,所以你主要index就是passengerID,requestID和wrote,requestID比较好理解就是你不停的requestPort他说这个不停的去扑他说这个这个不停的需要去扑他说看他什么情况了passenger ID 的话你可能就是另一种 request 就说我想搜一下我作为这个passenger 我的那个车票有没有 book 成功Route 是为了系统System scan你之前有多少个人book了,然后决定你能不能book到。然后这块有人问,静怡问说这个UID是hash什么?UID是hash车次啊?就是比如说G1234号列车6:09分,6月9号12点开车,hash车次作为这个,最后guarantee所有车次就是这个车次的这个request 最后到同一个database好就到同一个database然后所以呢,你做Book的时候你做book的时候实际上你只做了一件事就是在这个这个table里面碰到了一个肉你做就是在这个table里append的一个roll所以这个操作是很快的,就是append的一个roll,就是很快的一个操作你没有去看你跟谁在抢Resource你没有做任何事情,你就是在这个table里append的一个row然后假设这个read/write ratio是10:1的话,就是一个写十个读的话,那么这个QPS呢可能是10K,之前按1K来160K,不过即使是100K的话,100k 的话其实这个SQL Server是 handle过的, handle住的,一个单个的SQL Server是 handle住的,是吧?所以它这个一个SQL的Sharz是可以很轻松的 handle一个车次的,就是 resource competing的。然后当User book了 tickets的时候,我们就 return request id 了。那它可以asynchronize的去Pull这个request, 当然我们不想,因为这个client是我们可以自己设计的,就不能让它too frequent, 然后也可以加rate limiting和throttling, 然后我想说这个rate limiting和throttling一定要加在这个load balancer上,因为这个load balancer或者是lookaside的server上因为当你把这个request sharded到1000个server的时候,虽然你当前这个server可能来自于IP的request只有1,但1000个aggregate起来可能有1000多个request per second所以你这个load 那个就是sortle和这个rate limiting一定要在上面那层,或者是你单独有个专门做rate limiting的这个专门做 rate limiting, keep track of IPrequest per second的这种一个service,就是look-aside service,这样的话可以做regnancy meeting因为这个rate limit 长电操作,slotolent是长电用操作,我这块没有单独提。好像已有的12306 Rate Limiting做的不太好,因为我看到好多人就是程序员可以就是hack他那个system,然后能非常快的抢票,那如果他用程序来抢票的话,那肯定他Rate Limiting没有做好如果能用长序简报, 肯定 rate limit 没有做好。好,所以它这个,因为这个读和写不 block each other, 所以follow的读的话是不会, 就是follow up读是不会 slow down 写的。然后其次的话显示还有多少个 tickets available呢?就是一个简单的读,你不会影响写,所以不是book的 bottleneck,但是你读的可能是still data,但是我觉得现在user都expect你读的data可能不是最新的data,他们知道这个抢得很快。然后我觉得这个tricky part是有的user可以cancel booking出现多种情况看似我不停这种情况下的话你在 rating list 里面可能会被promoted比如说这种情况下的话当我book的时候我在这个book table 里面写了一个roll的时候可能会发生以下这种情况一种情况是你在这个stretchhold 之内那这种情况的话你就相当于这个ticket被你book掉了,你就可以return success
[40:00] 另一种的话是你在waiting list 之外,比如说是800个直达车次,你在前800个直达车次,就是说你book到车票了,但是你在哪个座位可能需要计算下来返回给你。但是如果说你在1000个座位,你在2000个以外,那你就可以直接return fill了,因为你不可能有车票给他,就fill掉了,然后waiting list number可以configure的。那如果你在waiting list 之内的话,你可能等个几分钟,等到1到5分钟之间,这个number也可以configure。如果之前的就是user cancel booking的话,你可以return success,就是轮到你来可以return success,否则的话timeout的时候return field,这样的话是可以保证这个。如果你说的wait list都清楚了,然后还是有一些empty ticket的话,你可以把这个车次再open up出来。这个好像也是常见的操作,不是经常就是你提早去book ticket的时候发现他之前有一些book很满的额外的空位了,这也是可能常见的。但是你在你在你在open up的时候,这个QPS就不会很高了,因为不可能所有人都盯着看,然后瞬间去make requests好然后这个座位分配呢我这块想的是用一个backend process, background process这个原因是,首先不能根据QPS来,因为这个QPS可能这个上线和下线都很高,你这个QPS如果是10万个QPS per second的话,肯定是不skill的。所以这个background process可以比如说每10秒处理一次当他去的时候就实际上出一次的时候他可以读到他首先可以读到configuration说从北京到上海有多少个测票在这个车次里面有多少个车票多少个 available然后他按顺序读,读到所有的book的,知道有多少个车票已经被book了然后再读哪些人在Q的前面还没有book到测票,然后他就把那个先说这几个人可以book掉了,那就把他这个write back of the table说book掉了。那哪些人是clearly out of the waiting list 了,直接fail掉。这个是可以做的,就是用background process来做这个decision。然后有人问为什么需要waiting list,可以直接fill吗?我觉得可以直接fill,我觉得我做waiting list的原因就是嗯提供一个稍微好一点的user experience,因为我觉得这个failure rate应该是挺高的,就特别直接book,然后fail的rate可能很高,fail的原因可能有多个,比如说你request就是从北京到上海,上海到广州是一个转程车票,然后其中一个fail的话另一个也应该fail,其次的话,当你request的时候,你可能刚requestbook完了以后,你可能要去刷信用卡,让你信用卡fill的时候,或者你的payment field的时候,你可能也需要mark field,其次的话,你book的时候有可能book出来,所以一开始的failure rate应该很高,所以我觉得这块设计一个waiting list,但我承认是optimization,可以把waiting list取掉,应该没有任何影响。如果一个车被Fully Book的话,它可以就直接在Configuration Server就说这个Unvailable,那你在看的时候就不显示它了,也不给你提供Book的选项了。然后它如果有新的空位release出来的话,你可以把它变成再available,然后再这个引起它book从技术的角度来讲,Technical就是Dynamic Allocation就是整个这个车票动态划分,就比如说有多少个册票是从北京到上海,从多少个册票北京到石家庄,这个其实是可以做到的。你就是不停的insert 然后用 background process background process 然后做已有的 limited information 的optimization是可以做到的好但是这个的话就是可能需要一个更longer的window,其次的话,我觉得并不复杂,其实应该可以做到的。然后有人问说,有人问说这个Background process怎么做? Mike问Background process怎么做?这个Background process可以这么做就是你就做一个那个你只要做一个distributed locker timer就可以了这种的话就是distributed timer,我还真没做这个,就是你做一个保证任何一台机器,就你可有个group machine然后Grooper Machine 任何一台机器就是在任何情况下如果有group machine其中有一个fill掉的话,其他的机器也是可以起来作为master,然后在每个固定的时间段issue一个request,然后如果是单台机器的话是Kronos,然后Brand说Cadence,Cadence也是可以的,Cadence就Uber开源那个也是可以的,然后如果你只是做这个的话,Kronos是单机的嘛,就是有一些Chrono这种application单机的,但是你在一个distribute system的话可能需要coordinate一下,像Salesforce有自己的service,Uber的话,Uber的
[45:00] 如果需要这种background process的话,我一般就靠那个cadence,或者什么这种这种,稍微craft一下就可以做background process了然后应该是这样子的我觉得这个 background process 并不复杂但是你需要应对的就是如果你有 single point of failure 的话你怎么样 restart backgroundProcess 这个稍微有一点点复杂,你自己写一个应该也不复杂的。然后如何确认整个车unbookable,这个cost会比较大不会啊,当你所有的说了这个sits全部book掉,没有人cancel的时候,这个车就unbook包了然后当你release的时候,有人cancel的时候,他不就那个什么吗?就是有available的并且你可以做这个车的onbook包,你也可以做旅程的onbook包,比如说你从北京到上海直达有800个,你虽然这个车有一千个座位,但从北京到上海直达是800个座位。这个全部book完了你就把变成就是unbookbook然后从北京到石下庄你还是可以book的你可以把它就是细分到车次加旅程,就是车次加这个其实点和终点这样做,我觉得也是可以做的。然后再一点的话就是你要book的话,cross-transit可能需要insert到很多肉到所有的table里面,比如说你要从就是你要去就是转成两次的话,你可能要insert到三个table里面。这样的话,如果有一个insert field的话,其他的chip应该automatically cancelled或deleted。所以这块的话,你转成的次数应该是有限制的,比如说最大是两次或三次。我没有用过12306,我不知道它是不是这个feature,然后最后的话这个data呢,当你这个车器开走的话,你应该把它move到一个historical log table然后使当前这个database非常令,非常非常非常瘦,这样的话你可以不停的就是server-in-request好,之前的booking呢,其实就是说,我觉得这个booking呢,就是把这个resource competing,变成了一个append problem。就是把一个非常就是10k的right每秒的这个resource computing对于每个车次就是对于每个测试,14000的Request Write 每秒,就是10000的Competing变成了一个single append的problem,我只是append的一个request,append的一个request,然后用一个background process去scan这个到底谁book到了谁没有book到然后用background process做decision就是book到了以后就是你book到以后然后再去分配座位所以这个background process,比如说我现在是个background process,我这一次判定有600个人book到了,或者200个人book到了,X number of people,是吧?我就把这个通过一个直接的request,或者是一个message queue都可以,就是发到这个Sate Allocation Server说好,这600个人book到Tickets了,然后他们分别book的是什么形状的Tickets那么您给它分配座位吧,然后它就可以怎么分配座位呢?首先这个set location可以花时间更长一点,因为作为一个user来说,你更多看法的是有没有book到tickets?如果book到tickets,我具体做哪,其实关系的不是那么多了,可以比如说再花额外的20秒30秒应该是没有问题的。但是有没有book到tickets很重要,因为没有book到tickets,可能需要去refresh你的request,就会额外的增加这个write。所以当他判断这个booked tickets以后呢,他就是把这个计划呢,你600个user可以用一个进程,用single process去allocate,那你就可以用简单的用dp啊或者graded都可以是吧,你首先你要做什么呢,就是因为你是可以single process嘛,你首先去读,已经allocate好的table,比如说哪些sits已经被占了,已经allocate好的table,那如果这个sitsallocate好的话,那你就是说在EU的基础上知道哪些sitsavailable,那你根据available sets,然后你一个single process,然后做一些简单DP和grading,那实际上这个,如果做DP的话,其实就是一秒左右。几百个的话,1000个的话,其实疫苗左右就处理完了。处理完了以后你再把它写进去,然后你这个sit就allocate好了。如果这个sit tablecrush掉的话,那么你可以就是从start的一个sitting table,那你这个从start的sitting table,你就可以读一下这个,这个,你就可以读一下这个,呃,可以读一下说我哪些人已经book好了,但我还没有allocate set,然后重新allocate set这个是可以只要放tolerant就可以的因为每个就是train的number是fixed的PenHive QPS呢相对来说也是proportional to Sys的所以相对来说
[50:00] 人是可以Infinently Scaled然后其次的话,如果这个SIT真的很高,比如说你发明了一个什么SuperTrain然后一个train里面有10万个seat,然后QPS在这个train上达到1M,那你还是可以把这个train车次加上后面加一个固定的数,比如说车次第一车向作为120,车次第二车向作为120,车次第三车向作为120。你还是可以就是把车次再break下来,然后按那个来shard,嗯,就是总是能找见一个很好的合理的sharding的一个granularity然后Alex问Payment那块可以和SET Allocation Server并列吗?我觉得这块是可以并列的,就是甚至可以先做payment,然后再做Sate Allocation,就是你book好鲜味饭的payment,然后再做Sate Allocation,我觉得这个是根据Use Case的使用情况了,因为我觉得你book tickets 的时候大部分 payment 应该都是 reasonable 就是属于能 pass through 的可能reject payment不是太多你可以allocate好了以后然后payment的就是付款确认了以后然后再返回处,如果payment fill的话,你就可以把seed allocation 给revoke 掉也是可以的,然后这块SATA location,因为它是个DP问题,你想一下它每个车厢这种长方形的,然后book 的测票数量可能是任何一个数但是不可能,很大也不太可能,就是比如说1到15都是可能的,那你确实需要一个DP去optimize,也没必要。我觉得因为它这个request,其实看那个request,如果是同一个人订票的话,这个number of tickets是一下reserve 很多的。所以你在optimize的时候,你用dpa optimize的时候,你能guarantee,almost guarantee,这个tickets买到一起的人能坐在一起。这是我的一个设计想法然后大家有什么comments吗或者是有什么其他的想法觉得这个能解决这个其他不一样的想法觉得解决这个也挺不错的有什么comments我觉得这个问题啊好,近话有杨阳说,12306的话是直接返回座位结果吧,如果要background process要延迟一段时间才返回结果结果。如果是这个的话,你实际上差不多要,我们可以算一下。如果是这个background process,首先这个是configurable的,如果这个background process是10秒run一次的话。你request过去是一秒钟,写的话就是四手五路一秒钟这个background process is configurable 10秒钟 run一次然后它run好了以后然后这个batch去allocate作备再花一秒钟,差不多12秒那这个12秒其实就纯粹看这个Bagrand process都就run一次了,如果这个Bagrand process5秒钟run一次的话就可以比较7-8秒左右反汇。所以这个好像也没有很很有问题,我觉得还是skill的。我不知道已有的12306怎么做的我没有读到这个他已有的怎么做的还有一种做法还有一种做法是我想到还有一种做法是什么呢?我想想我还有一种做法是小金 我记得我们讨论的时候 我之前讨论的时候还有一种做法 你记得是怎么做吗有没有什么想法好然后陈肖问说,AuterIncrementalID是在SingleDatabaseShare上吗?如果Global怎么实践?嗯你这个Single Incremental ID 其实没有Global的问题, 因为你实际上来说, 你对于同一, 这块其实你想的是, 你有M个人对N个资源进行,CompetingM个人就是所有想从北京到上海的人对于北京到上海的测票进行competing那么他的所有的request呢实际上到具体的测试上是到同一个database的到同一个database,所以当你这么share的时候,你其实是不需要global coordination的所以这个AlterIncreaseID相当于是个QNumber,相当于是个RequestNumber景祥,我看你这块说,可以把batch变成每个request会把当前还没有处理的座位一起处理而能解释的观念
[55:00] 我们听不到你说啊啊 听到了吧现在听得到我现在不是有一个背光 process 不断的批准那些座位的问题吗?好其实可以让我觉得可以让就是比如说你现在有100个人在已经summit了这些allocation然后让这100个人第一个就是他比如说,他100个人已经在数据库里面填完了然后第一个其中的随便一个进来然后就把这100个全部处理了然后一起放给所有了啊 ok 但是这样的话呃随便说办法Event就变成了就是一个鼓一个鼓的处理,然后每一个鼓有自己的leader,有一个leader的一个Leader的一个task 去把剩下所有task一起处理谢谢大家我懂你的意思就是每个insert的时候比如说就是insert然后你看到你的ID是多少比如说你ID是一个固定的值100然后你就把之前的全部处理掉是,每一个就是把它之前全部除了?但是我觉得这个还是有问题的,因为我直观想到的问题就是因为这个request太多了,所以100,200,1000可能是同一时间出现的。那100这个是处理1到100的吗?还是1000也要处理1到1000的?还是处理901到1000?主要是每次都有一个人出来把没有处理的全部处理掉就好了。就不需要一定是神 也不一定是比他大比他小好那是你自己的其实和Background Process是一样的其实是很像,但是trigger的不一样在配光Police独立的一个技能做这个是每一个技能进来都来做这件事情然后就那个这么说这其实并不需要一个我想一下好其实这话也可以做一个Message Queue这种冲例,就是说,就是弄个Message Queue,然后Message Queue Worker的话就是,啊好但是Message or Asynchronized 可能同时有多个处理说白了这个就是这样子就是你只有一台机器顺利它处理然后只有一个进场进行处理就可以了其实两个意思差不多啊,我说这个东西可以不用那一筹外光窝口谢谢大家谢谢大家嗯,行,我觉得意思是一致的,就是其实意思还是一致的,没有本质的区别好,最快有 CWCW,我们。多个分段的车次比如说从上海到书州到武汉到济南到北京请求比较多,短阶段请求比较多,这种协力分布对于系统最大影响在哪?如果我理解对的话,就是这个其实这个从比如说从武汉到几年有多少测票,它是根据历史数据来分的,就是它一上来已经分好了。所以它是不属于工程问题,从工程上来,比如说从从engineering 角度,从武汉到几年,比如说它的车程是B1,B1就是500个票,这个票已经之前按历史数据,historical data已经分好了。所以,在这种情况下,其实对系统,我觉得影响其实其实影响就是说你把这个问题可以更细分化,你比如说你可以把车次加车层作为hash key来hash,所以说你这个比如说你从北京到上海那你从北京到上海直达的和从北京到武汉中间一半这个就是从武汉到北京这块是其实在可以分到两个完全不同的事了因为反正他们数量是固定死的他们在自己的pool里面进行competing也不直接进行competing他不会说北京到上海这个直达的book完了,我就book北京到武汉,也不会说北京到武汉book完了,就暂用北京到上海的这个直达测票,这个是就是那个之间book competing的。所以你把它细分的很细的时候,你可以share的时候,也可以share的很细。其实我觉得如果你按车次然后再加那个起始点中止点来shard的可能会shard的更细一点,可能会让这个load更balance一点那么每辆车的SAD数是在脸数的平方级别,那应该没问题啊,你这个像Uber的事儿的,scheme list 1000个,
[60:00] 其实也不是太夸张4096个,UberSherz4096个,一辆车站点就10个的话,你按平方级别就100个,就是放到100个Sherz上,我不觉得是个问题啊,一个车次的话Sherz放到100个上面,不觉得是个问题。谢谢大家如果按照AltreIncrease ID的话来决定是否买到票那么很多台机器都相同的number这个不是问题啊,因为你其实只有在箱头的机器上才有competing的那个才有competing的那个什么,如果你在不同机器上的话你是不compete的,因为你不是同一个资源铺,一个resource铺的。你在不同机器上说明你要不是同一台车次,如果按这个设计的话不是同一个车次,或者是你是同一个车次,但你其实点综织点不一样,如果你稍微的更细分的话那你这样的话你本身也不直接compete,所以没有必要有Global Queue。然后其次,这块设计就是Avoid Global Queue,因为Global Queue的performance很糟糕,这块有Global Queue的话,也没有说performance很糟糕吧,但是我就没有必要有global queue然后要问放 background process 的话一直跑是不是比较 costly?毕竟不是一直 peak,相对 message queue 有什么优点吗?Message queue 是做 find out 的,就是你一下 queue 一大堆 request 然后然后那个然后不停的有这个你可以比较elastic的调节有多少个worker去处理这个request是比较方向的过去的Background process的话这种情况下你肯定要放Background process 因为你需要用一个process来做DP吗你需要去读到你需要做resource allocation 你需要一个process做DP吗谢谢大家然后可以用一些,HX说可以用一些Buffer的WriteTrick,然后像Schemeless一样,to increaseWriteAvailability。如果按这个设计的话,其实每辆车Write其实就是10k每秒。10k/s其实非常小,按一个扇的处理能力其实非常小,还是能处理的好,然后李方远这块提了一个alternative solution,方远在吗?谢谢大家方言不在啊 提了一个alternative solution我没有读懂这个alternative solution是怎么回事,我觉得是不work的solution,就比如说说是不在relational database上做critical bus,因为relational database scalability是有上限的Reallitional Database,我个人觉得是可以InfiniteSkill,因为你像Uber的话是分成4096分如果你做一个简单计算,4096,4096乘以每一台机器可以做10k的transaction per second的话QPS的话你实际上是有400个Million的QPS可以支持,基本上算InfiniteSkill,并且你这个LayerSystem可以做多层你这个sharding是可以做多层的,所以这个relational database skill 其实不是一个问题,其次的话这个skill 12306需求也不是到这个skill的,就是没有到它skill的这个波投Nike,其实一个测词上波投Nike还是没有到的然后 pre-allocated tickets把没有卖的 tickets的portion放到一个server上server从内存里server request,然后一步update回去给database。那就用一个in-memory database update了。你memory database update 性能是可以满足的,但 durability 会有问题,然后你返回的时候,你返回的时候,Deerability会有问题请不吝点赞 订阅 转发 打赏支持明镜与点点栏目你返回的时候 Durability 会有问题你如果是在写到 In-Memory 的话request 应该是没问题的,就是你这个10k的request per secondsecure request per second的同一个机器你看多久返回了对,这块其实12306这个设计就是Large Scale Ticket Booking System,其实QPS不是关键,我觉得说的很好,HX说的很好,QPS不是关键。你需要管的是多个人对于resource进行competing的时候怎么样分配这个resource这个是观点QPS其实当你shard以后,它不是一个很好很很重要的问题好Pre-allocate的话容易Under-sell,那么减少Under-sell,Allocate的时候可以做Demand Prediction但是 heuristic 最好像就是火车站的时候做的如果解决不均匀,那就各种load balancing好了Client side加L4 load balancing,L7 load balancing,这样所有的票都满了,有的收入都没了
[65:00] 这块的话我觉得这个data其实你data是在database上作为stated,你load balancer只是charging,就是request,你不管有多少个load balancer,有多少个application server最后到Datapace上你同一个车次的同一个起始点中止点的request还是最后到同一个database上的host 上有 agent 解决 local tickets 快慢玩玩是 request 或者很久没留下release 一下我还是不懂什么意思啊,好,还有Available的问题,如果有一个server挂了,分到它的ticket被站着,别人没办法买怎么办?这块这个server你要看,按我们这个设计的话,所有的application server的stiteless挂就挂了然后database是不能挂的但是Database的话应该是,首先Database挂的概率相对低一点,其次的话如果你真的很担心挂,你可以在那个就是synchronize say,replicate一份。但是default的话都是asynchronized replicate,因为这样的话request时间快但是你可以synchronize the replicative 。我想说一下这个设计里面,其实你只有当你返回,就是如果你这个用户这个state没有book的话,你是可以Lost data的你是可以Lost data的 就是你没有变成booked的State 你是可以Lost data的你什么时候不可以loss data,就是在book确认了以后你是不可以loss data的但是你没有book的话,你就可以lost data,无所谓,在request过来的时候,我没有request,我就是说没有book成功就可以了嘛。但是你book了以后是不能lost data的所以这块你replicate,就是你这个server replicate甚至可以这么做你Background process scan 的时候说我觉得这个人不考 tickets 了然后你这个ApplicationServer去几个Replica看一下它这个book有没有写入,如果book写入了再返回也可以。就是你先去确定这个book写入了,就是这个number of replication 大于1,再返回,yes也可以。如果你不担心这个就是非常small chance,就是比如说1/1/11的这个loss data的话,你其实Asynchronized Replicate也没问题所以这个high availability也不是问题,fought tolerance也不是问题谢谢大家谢谢大家如果一个server挂了,卖出去的票没有来得及及时update怎么办?人可以问问PM我觉得这是Engineer问题不是PM问题然后可以后面加一个memory-based database,比如Redis这个用Redis是可以搞定的,但不是很好,因为Redis所有的Write是到Single Thread上的所有的Redis Thread是在一个Single Thread上解决的。也就是说你RAID的时候,Redis是有多个thread处理你的RAID的问题,但是你说的Redis thread是在single thread进行的。虽然它guarantee serialized transaction,但是你这种情况下,你瞬间给Redis single thread加了很多写。虽然它这个数量其实很能够的,Redis每秒钟大概能处理简单的write是10的5次方的write,10的5次方每秒钟,Redis是没有任何问题的。虽然能处理掉,但我总感觉不是一个很好的设计。其次,你用Redis写的话,你本身就没法guarantee fault tolerance问题,没法guarantee durability问题。谢谢大家然后我读了下这个paper,我读了下这个load balancer paper,我觉得还挺有趣的,那个load balancer paper 还挺有趣的,它是是微软又嗯微软用这个commercial machine 来替代传统的load balancing的一个过程,我觉得这个paper写的还是挺有趣的,像这个传统的load balancing呢是有rote management,就是你管怎么样去charge road,然后有health monitoring,看说哪些application还活着然后你对于inbound package的话你要决定它的destination,然后你对于outbound的话你要决定你要决定这个怎么样就是怎么样把它就是做request返回是吧,就比如说我现在outbound的话,我要决定怎么返回给哪一个requester然后传统的这个load balancer呢其实他是有一个非常自己专门做load balancer的hardware做的他们这个hardware非常贵啊他这块写了8万我记得我上研究上的时候说20多万就是一个standard的那个commercial的load balancer是20多万美元的是非常非常贵的所以它后面有很多就是这个是
[70:00] 第三年左右嘛,就是研究所那会有很多那个Solution是用commercial非常便宜的机器来取代这个Expensive Load Balancer这是他们其中一个努力之一然后它这个设计也很有趣它这个设计很有趣,它设计的时候是,它是多层的,第一个Tier就是这个叫EcoCost说白了就是对于他所有的注册这个MutexMultiplex就是评分,就按这个评分,他也不考虑什么package,就评分然后这个Multiplex呢是会把你这个request分到你的service上,然后它这块是用Virtual Machine的,没有用什么Kubernetes啊,Docker啊,他会把你的request分到你的server上然后这样的话你这个request比如说是同一个transaction或者同一个connection的,那你第一个request的,进行multiplex可能是分到1的,第二个request可能分到这个multiplex,但是它也会分到1。因为它这个就是有一个header是一致的,就是同一个connection然后配到一起,然后它在里面再处理,然后它处理的时候呢,它实际上是把EU的load balancer就把它分开了,用新的一些series来,说白了是用software来解决hardware load balancer的功能,或者解决那种commercial load balancer machine 的功能然后它的outbound ticket package 是是避开这个Multiplex的我觉得这个设计是有可取之促的,但是我个人觉得Uber设计更好,因为这个其实我个人觉得SRE这块理解不是太深容但我读这个paper 我感觉这个是替代了最早的那个就是load balancer就是那种commercial的load balancer,非常贵的load balancer,一个GPG20多万然后他用这个用software来替代了那个commercial load balancer。但是像Uber这种,我觉得Uber这个设计还是挺好的,就是Ober有个叫RTAPI 所有的outbound全部通过RTAPI来进行你这个verification,然后从RTAPI里面读取你的ID信息,然后对你进行verify然后读取ID信息然后验证就是authorization authentication然后验证是你以后,然后根据你的ServiceName来lookup这个Service wrote到哪儿。然后这时候就是用JRPC或Sriff的那个Service Lookup Service然后Uber Lookup Service好像是应该是SIG Client什么意思呢?就是他每个Client其实有个自己的Lookup,就是从Client端就有个Lookup Knowledge知道去哪里找你的service如果这个他那个autodate的话Client autodate的话他会去Rulekeeper寻找最新的Uber内部专门有个Service叫Martin, 底层的实践的话, 应该就是每个Client的端是有一个Mapping的, 比如说我要靠ServiceA, 我就把我的Request全部Pot forward到ServiceA对应的是Pot12345,12345这个POT呢,然后我就lookup说,这个POT request到12345,12345又forward到哪一个IP的地址,然后哪一个POT number然后进行request forward 如果这个不work了 那我就需要去读我下一个available的node如果这些都AutoData的话,我要去Rootkeeper上拿到最新的,因为Rootkeeper是个Configuration,Global Configuration,去Rootkeeper拿到最新的这个Service IP address location,然后我就 forward or require 最新的那个Service就用那个Rootkeeper来keep最新的configuration就说了这么多,我就说这个感觉是一个load balancer的一个work,但并且这个work好像感觉已经有点过期了我读了一下这个Payment我觉得写的还是不错的,从2013年的贝利塔写的还是可以的。好,我今天就讨论这些好了,我没有什么额外的要讨论,大家有什么问题吗?或者有什么额外的想贡献呢哈雷问说所有的load balancing的client怎么保证mapping的一致性,mapping的consensus实际上是用root cable这个consensus进行实践的。你入kaper就是专门做consensus的比如说当你有一个新的node,我们说Roopkeeper,就是刚才讲过就是Roopkeeper擅长做两件事嘛,一个是configuration,也做membership management,当你有个新的node加入的时候,说这个node说我负责service嗯我负责service,就是service A,然后我这块有我的IP是多少是吧,我的那个Pol number是吧,
[75:00] 那么我看一下这块有没有个例子OK就这个例子这个例子,比如说这个我现在是有个roting layer 我说要去拿那个然后我就有个routing layer,这个说白了在Uber里面这个routing layer和这个client server是同一个,internal service是同一个,这个routing layer就是multi他会说我先去Node2去读是吧我去这个Note 2去读因为这个data在Node2上然后但是如果这个Node2没有或者它dataAutoData的话他去入Kaper拿最新的data那如果这个Node有新的Node加入,会有旧的Node退出,会有Node更换的话,那Node会更换。就是inform rootkeeper 然后当他就是当他 ready 的时候会 inform rootkeeper所以这样的话你永远能从最新的Rootcabular拿来的Source or Choose然后因为这个commercial所以你的这个commercial database,所以你这个是自己internal的嘛,所以它这个fill的概率很低,怎么知道autodate很简单,因为你Uber内部不是请求的时候,你就是请求pot12345然后进行request 你是个grpc call 或striple call你如果AutoDate的话,你这个server已经没有这个docker了,你就不可能去服务你这个你这server已经没有这个docker去听着这个port number了你就不可能服了就直接就Service is not available,不就AutoData了吗?当它AutoData的时候,这Marketing应该自动trigger一个update就可以了好如果在Multi-Late组或者是Infra组工作的话,你可以share一些更多的insights,但我直观对我Multi-Late理解就是这样子的,并不用很复杂,就是一个rich plan,比较一个secret plan。好好 如果没有问题的话 今天就讲到这里吧我还想说这个Design YouTube这块还是有些复杂的嗯我就是做了一些这个CDN的research,我觉得还是挺有趣的,比如说Twitch的话就是30秒一个Cliff啊,豆瑜的CDN就是同一个file,然后它会不停的喷着新的东西啊然后YouTube的话,它是用自己的encoding啊,然后它自己用自己的encoding,我也没看过它format是什么,但是它好像大概每三秒还是五秒就是code一个claps,然后你去那个去那个update我这个可能还需要点时间再写啊然后我下周可能跟大家分享一下Design YouTube然后并且你直接打开YouTube,或者打开斗鱼,或者打开Twitch,你会发现他们实践方式是不一样的他们时间方式不一样的,直接看就发现他们时间方式不一样的。可能多个时间方式,到时候我要有空的话也把多个时间方式列一下,然后讨论一下。好谢谢大家好今天就说到这里吧谢谢大家