讨论以分布式系统底层的数据冗余机制开篇。主讲人指出,在诸如 Cassandra 和 DynamoDB 这样的分布式数据库中,副本(Replica)与数据冗余的核心目的是为了在并发读写时通过多数派仲裁投票(Quorum Voting)来保障系统的线性一致性(Linearizability)与高可用性(High Availability)。以经典的 Dynamo 论文为例,其底层使用的存储引擎是 Berkeley DB Transaction Data Store(后来亚马逊虽然更换了底层引擎,但核心原理未变);数据库引擎自身已经能确保落盘数据不会发生静默损坏(Data Corruption)。因此,数据库层的多副本设计绝非用于修复损坏文件,而是为了容忍节点下线或网络分区故障——即使某些节点失去响应,系统仍能保证读取到最新版本的数据。
API -->|"Generate Immutable Submission ID"| SQLMaster
SQLMaster -.->|"Async Replication"| SQLSlave
API -->|"Store Raw Code & Payloads"| ObjectStore
end
```
- 任何关键服务都不能只部署单节点(Single Node),否则该节点一旦宕掉就会导致服务不可用(Unavailable)。
- 在整个系统中,绝大部分服务如 User Service、Compute Service 都是完全无状态的(Stateless),遇到高并发或算力不足时可以随意水平加机扩容。
- 唯一必须严格维护状态的是底层的关系型数据库;即使用户的 API Token 存在服务器内存中,由于节点故障是低概率事件(例如上百天才宕机一次),即便偶发宕机也只需让用户重新登录(Force Re-login)刷新 Token,不会造成灾难性后果。
## Notable quotes
> [00:00](https://www.youtube.com/watch?v=_eRTl_YxgUw&t=0s) 在系统设计中建立正确的思维模型至关重要:在假定没有拜占庭将军问题的前提下,计算节点本身返回的结果默认是可信且正确的,唯一的例外是时钟(Clock)。 — Scott Shi
> [00:00](https://www.youtube.com/watch?v=_eRTl_YxgUw&t=0s) 系统设计非常讲究这种“螺旋式思考”,很多问题初看可能考虑得不够全面,但随着不同观点的碰撞和对各类数据库底层逻辑的推演,理解才会逐步深化。 — Scott Shi
> [05:00](https://www.youtube.com/watch?v=_eRTl_YxgUw&t=300s) 以往设计的系统绝大多数是数据密集型(Data-intensive / Data-bound / Database-bound),瓶颈在 I/O 和数据库;而 LeetCode 是典型的 CPU 密集型(CPU-bound)系统,其最重的计算负载完全落在 CPU 运算与代码沙箱执行上。 — Scott Shi
> [20:00](https://www.youtube.com/watch?v=_eRTl_YxgUw&t=1200s) 如果你去柜台点咖啡,服务员必须花 5 分钟做好咖啡亲手递给你才能接待下一个人,系统可用性(Availability)就会极低,排 20 个人就得等上很久;但如果服务员先给你一张小票(Receipt),做好了你再去取,系统的吞吐量和可用性就会显著提升。 — Scott Shi
> [20:00](https://www.youtube.com/watch?v=_eRTl_YxgUw&t=1200s) 如果真有恶意攻击者想要搞垮 LeetCode,其实“并不是很复杂的一件事”,但自己作为一个守法公民(Good Citizen)自然不会去干。 — Scott Shi
> [25:00](https://www.youtube.com/watch?v=_eRTl_YxgUw&t=1500s) 实际软件研发中,单写原始代码可能只要一个月,但后续针对生产环境的 Rollout、Service Maintenance 及 Bug Fixing 往往要花上三个月,这才是消耗工程师精力最多的核心阶段。 — Scott Shi
> [30:00](https://www.youtube.com/watch?v=_eRTl_YxgUw&t=1800s) 此处绝对没有必要使用 Cache,因为评测结果具备很强的即时状态流转性,引入缓存不仅会导致结果脏读或延迟(Latency),更增加了不必要的系统复杂度。 — Scott Shi
> [40:00](https://www.youtube.com/watch?v=_eRTl_YxgUw&t=2400s) 干脆把整个 submission 表全部放进 MongoDB 等文档型数据库,因为其单个 Document 上限有 16MB。这是一个明显的糟糕解法(Yellow Flag)。 — Scott Shi
> [40:00](https://www.youtube.com/watch?v=_eRTl_YxgUw&t=2400s) 绝不可将源码直接存放在裸本地文件系统(Filesystem)中,因为缺乏完整性保障容易发生数据损坏(Corrupted),而 S3 等专业存储自带高持久性保障。 — Scott Shi
> [40:00](https://www.youtube.com/watch?v=_eRTl_YxgUw&t=2400s) 业界共识是只要业务数据模型规整且单条尺寸可控,应毫无疑问首选 SQL(No-brainer)。选用 NoSQL 必须给出极强的前提证明(Justify)。 — Scott Shi
> [54:55](https://www.youtube.com/watch?v=_eRTl_YxgUw&t=3295s) 就跟打球一样,一边要学理论一边要搞实战,实战还是很重要的 — Scott Shi
[0:00] Scott Shi: 在系统设计中建立正确的思维模型至关重要:在假定没有拜占庭将军问题的前提下,计算节点本身返回的结果默认是可信且正确的,唯一的例外是时钟(Clock)。
[0:00] Scott Shi: 系统设计非常讲究这种“螺旋式思考”,很多问题初看可能考虑得不够全面,但随着不同观点的碰撞和对各类数据库底层逻辑的推演,理解才会逐步深化。
[5:00] Scott Shi: 以往设计的系统绝大多数是数据密集型(Data-intensive / Data-bound / Database-bound),瓶颈在 I/O 和数据库;而 LeetCode 是典型的 CPU 密集型(CPU-bound)系统,其最重的计算负载完全落在 CPU 运算与代码沙箱执行上。
[20:00] Scott Shi: 如果你去柜台点咖啡,服务员必须花 5 分钟做好咖啡亲手递给你才能接待下一个人,系统可用性(Availability)就会极低,排 20 个人就得等上很久;但如果服务员先给你一张小票(Receipt),做好了你再去取,系统的吞吐量和可用性就会显著提升。
[20:00] Scott Shi: 如果真有恶意攻击者想要搞垮 LeetCode,其实“并不是很复杂的一件事”,但自己作为一个守法公民(Good Citizen)自然不会去干。
[25:00] Scott Shi: 实际软件研发中,单写原始代码可能只要一个月,但后续针对生产环境的 Rollout、Service Maintenance 及 Bug Fixing 往往要花上三个月,这才是消耗工程师精力最多的核心阶段。
[30:00] Scott Shi: 此处绝对没有必要使用 Cache,因为评测结果具备很强的即时状态流转性,引入缓存不仅会导致结果脏读或延迟(Latency),更增加了不必要的系统复杂度。
[40:00] Scott Shi: 干脆把整个 submission 表全部放进 MongoDB 等文档型数据库,因为其单个 Document 上限有 16MB。这是一个明显的糟糕解法(Yellow Flag)。
[40:00] Scott Shi: 绝不可将源码直接存放在裸本地文件系统(Filesystem)中,因为缺乏完整性保障容易发生数据损坏(Corrupted),而 S3 等专业存储自带高持久性保障。
[40:00] Scott Shi: 业界共识是只要业务数据模型规整且单条尺寸可控,应毫无疑问首选 SQL(No-brainer)。选用 NoSQL 必须给出极强的前提证明(Justify)。
[54:55] Scott Shi: 就跟打球一样,一边要学理论一边要搞实战,实战还是很重要的
Original transcript
[0:00] to record. Oh. Oh Record, okay. Just to hold the phone, it can be done with you data. But for the存在, it has a different purpose. In Cassandra and DynamoDB, the duplicate is a red column column. It is for you to be able to do and write when you read and write. The core is the vote. This is the vote. This is a simple way. For example, we use Denimal paper. Denimal paper, the database is the Berkeley database transaction data store. It is a Berkeley database. It is a data store. It is a data store. It is a data store. It was a data store. I heard it on Amazon said that he changed a data store. But you can see it in the bottom of the database. It has a database store. It has a database store. It has a guarantee that the data is not been corrupted. So the duplicates actually is not used to handle corruption. It's not to handle corruption, it's to duplicate. For handling availability, for increasing availability, for example, duplicate the sample. I can write two of them every time. I read the two of them. If I read and write two of them, I can guarantee the latest data. I can guarantee the latest data. I can guarantee the latest data. I can guarantee the latest data. So the duplicate, it's used to guarantee linear ability. And the duplicate case design is also increased availability. If you have a node, if you have a node unresponsible, it's not responsible. Unresponsible is node or network is not responsible. So this duplicate shows but in file system you can use file system. You will not have abstraction. You file system, any file can be crafted. For example, you file system is written in SSD or HDD. It is written in disk or in the固体硬碟. You can be crafted in this file. When you craft it, Actually, it's not a database that says you have this record crafted, and you can crack it, and you can use some error correction algorithms or something. It's not a database to guarantee this. So when you read this file, you can use incorrect data or crafted data. So the usual way to use check sum. or hash This is a guarantee, if you have a bit of a file, If you change the hash code or check sum, it's not the same. to test the file. So in this case, the duplicate case is often One is also to ensure that you have a copy of a single point failure. But in the other hand, it is not a database as a guarantee. So you have a duplicate, every copy is data. You read it, you must compare with other duplicate. You must compare with the check sum. You have a different section with check sum. You can compare with other parts. And then the last is P2P system. This P2P system is an object store. It's an object store. It's an object store. The node is a disconnect at field. Any time there will be a new node. It will be disconnected. So the file, and the底层, is a file system. So you need to check the correctness. You need to check the correctness. So the duplicate case is used in different places. There are different tools. In file system, you must run check sum, and see if the file is not a problem. But if you build the service on the database, the database is guaranteed to guarantee you the data is not corrupted. Because in design, you just think about this. In the first time, when design, computer runs every single node is guaranteed. One is you return the correct result, and you will not return the wrong result. You won't return the wrong result. The exception is clock. Clock will return the wrong result. Because clock is hard to define the source of truth. So clock's answer, clock's result is You can't rely on clock results, even if clock is spanner, you can know the arrow bound. You can see the arrow bound, upper bound and lower bound. Yeah.
[5:00] 就是有一些discussion,我觉得还是比较有趣的,我觉得这个system design里面就讲究这种螺旋式思考,有时候开始的时候可能稍微弱一点,就是你开始的时候可能就是思考的时候有一个地方没有思考全面,然后你在不停的思考的时候,就是有有心的问题思考的时候,然后包括有人不同观点的时候,就是这个有一定的就是你自己的理解会不断的深入啊,不同的database的理解会不断的深入。好我们这周的话就讨论leetcode我可以看一下lead code in case大家没有用过lead code嗯List code的话,这边的话我们主要就是implement几个feature,首先你能看到List of problem,比如说你点开List of problem,你能看到这个list of problem,就是有一些哪些问题啊,然后有一些hard,medium,easy啊什么的。这个Lead Call Account也是我几年前做的一个,我当时是把收货题都做完了,可能做了600多题。但是反正就是连续的把所有题都做完了还是有一些还是挺有趣的然后我觉得这个database其实有的也挺有趣的,像我们system design的话,这个database可能需要理解比较深入一点。我推荐大家没有做过的话也可以做一下然后如果你设计Code的话,如果你有Fill的话,你需要return一个properErrorCode。然后其次的话,你可以自己define你的input/output,比如说我们随便找一个我们随便找一个随便找一个铁 to sum 好了在这面的话你应该有一个应该有一个有段时间没用了,有点不习惯,好,我看一下,debug code in background, run default ratio last code, edit shortcut,这块你应该是可以加一个input的就是expected input和expected output的就是下面的console对好的好的好的我有段时间没用了就是你可以 define 这个 input 和 output 然后其次的话 你可以看一下过去的 submission 比如说你可以看一下过去什么时候 submitted 过是吧 这种然后呃你可以看 runtime distribution 比如说对你其中一个 submitted code你可以看一下你的Runtime Distribution在什么在什么水平之间是吧,然后你也可以看到memory的这个distribution在什么水平之间好,然后其次的话,这个feature是比较新的,我昨天才留意到,就是你可以在这个console里面debug code在 console 里面 debacle 这块的话看起来好像在你的 browser 里面 run 的 但实际上它还是有一个 rest api endpoint好,我们说这个就是System Design里面就是你需要花很多时间去understand business,use case,common sense,你可能需要不停的问面试官,像这种情况下我觉得lead code相对我们大家都比较理解一点,我可能就会跳过了。constrents的话我简单估算了一下这个Litcode,就是我看了一下它这个cap的话,Runtime大概是200毫秒,然后memory是200MB。其实它更小我看它这个CAP的memory好像就是个42MB是比较小的,我这块是假设200MB。它其实是和我们之前设计的系统都不一样,跟我们之前设计的,不管是12306订票系统,还是YouTube,还是Crawler,那些都是data-bonded。说白了都是data-intensive application,都是database-bonded。这个里面的话它其实是CPU-bounded的,所以它的所有的heavy part都在CPU上面。所以说这个系统和我们之前设计是不太一样的。然后这块的话我假设有10万个Data User,作为一个Reference的话,好像美国是有400万个Programmer。很像比较热门的一些从事员找工作的网站的话,比如说TripleByte这种是有20万个Engineers,是吧?我计划就假设10万个Developer,Shrang user的话,然后每个User,Active user的话,每天是有10个Submission那这样算下来的话大概有一个million的submission那一个Million Submission的话,如果换算成每个都是跑到200毫秒的话,你实际上这个系统的计算时间就是它这个highway loadHeavy-Live compute 的时间的话是一天是28秒,那算下来的话,如果平均下来的话,average 的话可能是需要三个 docker,或者是Virtual Machine就是20万除以每天是86400秒如果consider peak to normal rate 可能是三个的话,我们可能需要6-9 docker during peak time,那这个并且这个可能需要,你可能需要一些elastic这种 scalability 是吧,就是你是比较
[10:00] big time的话你可能是多一点这个machine然后你不是peak time,可以少一点machine,但你这个compute的这个machine可能就是需要6到9个docker就可以了然后其实这个量不是很大,这个量真的不是很大,可能你需要三台模式,差不多一个模式,两个docker,或者几个docker,其实就可以handle了,这个量不是很大。好,然后我们再看这个requirements,这个go的话应该是,首先是high scalable的,因为这个白天和晚上这个是明显有作业周期性的嘛。就是晚上肯定没有人去设计 code然后白天的时候设计的 code 可能比较多然后context的时候参加的人的时候是比较多的像我看这位Edy同学说context的时候15000人peak time 所以这个10万的这个user还是远远大于这个context的人说的然后我们这块不讨论的话,首先是high scalable,其次是scalability需要非常Flexible 是吧,人少的时候,有很多经济在空转的话会浪费很多钱,所以人少的时候你可以把机器再减少一点,最好能elastically scale 是吧,但是不行的话,比如说你就固定的schedule一下也可以,或者是你可以detect,比如说你这个机器的话,CPU utilization rate 大于50%,你就新建一个新起来一个新的worker也可以,然后其次的话,how available,当你想去submit的时候,你总有机会去submit它,你不必要是有机会的,除了这个Service unresponsive我不知道现在LeadCore怎么样但是我几年前用的时候,四五年前用的时候,它总是非常容易unresponsive,我经常就不response了所以它的availability还是多少有点问题的然后我们不讨论了,这里面不讨论,一个是comments,就是这个comments我们在YouTube,然后在那个slack里面已经讨论过多次了,我觉得这个有很多duplicates,所以就不讨论了。然后其次的话,Server side authentication and authorization 是不讨论的这个其实是一个单独的议题,就是你Outh,Outh是一个单独的一个问题。我们就不讨论了,然后这个server side的sortle也是不讨论的,这个rate limiter和sortle也是个单独的问题。如果有计划我们可以讨论一下,但在这个问题里面就不讨论了。我这块设计architecture比较简单,其实它这个系统确实比较简单,这个里面的话,所有的API requests都要去API Gateway这个API-GitFace要做多件事情,它比较做rate limiting,要做OAWS check,表示你是一个valid user,你可能同时,这个API Gateway有多少有点load balancing的功能,就是它把这个request balance,比如说你这个user service有两个node,它这个user service是stiteless,所以你就可以把request balance distributed到这两个node里面,然后这是这个load balancing,就是API Gateway它主要做rate limiting OOS load balancing这都有通常解决,我们就不在这讨论了。然后这个设计里面有几个重要点,一个是首先是No Single Point Failure,任何一个东西,就是在你设计任何东西说,你可能只画一个service,比如说只画一个API Gateway Service,但是你一定要临界,它其实不是一个node,可能是多个node在后面。它不是简单的一个node,比如说这个work queue的话,这个work queue的话,这个就是当你summit code的时候,你就把这个codesummit到work queue里面,这个code里面呢,其实应该是,应该是这个,因为它是个kafka嘛,所以这个kafka本来就有scalable这个功能,你可能是有多个node去hold Kafka的保证你如果一个single note down的话,这个Cafrica topic还是要available的有人说让我放大一点谢谢大家好 这样应该好一点好首先要注意的是一定要有No Single Pied Failure, 这里面User Service和Compure Service是Stateless, 意思是如果Service down的话它是没有任何State的然后就没有任何 state,所以你就是需要就是就是你意思是你可以随便的 bring up worker,就是可以增加这个 worker 数量,特别这个 compute service 是不应该有任何 state 的这个情况下如果你load比较高的话你可以多加几个node去计算这个submission,如果load比较低的话你可以减少几个service然后这个API Gateway的话,API Gateway是有Active User Token的它可以成ActiveUserToken,或者是你可以把ActiveUserToken放到一个InMemoryDatabase,比如说Redis或MemCache,然后你这个APSGateway呢是比如说你如果要查这个User是不是ValidToken的话,你可能先去Redis和MemCache里面,lookup这个Token,然后说这个Token是Valid以后,然后你再继续设众其他Request。
[15:00] 这个token不是vallet的话,你这块就应该终止掉了,就应该return emellied access,或者是request unauthorized access,401这种error然后这个API gateway也是多个server的,只不过这几个多个server呢,如果不是stateful的话,如果你不是 stateful的话你是你需要look aside,就是look aside去那个in-memory database 去查你的token这块的话,你防止single-point failure其实非常简单,你只要有一个backup API gateway service就可以当你major service go down的时候,你就backup起来就可以了。如果你这个API Gateway service down的话,user可能要去backup那个API Gateway service,这时候你的token是可能被lost的,如果你存在in-memory的话存在in-memory token的话,这个token可能会loss,那你这样的话可能需要false re-login,这个不是一个主要的意想,因为毕竟这个service down的概率,就是这个机器down的概率是非常低的。然后这个Online Compound就是我们看起来像是在browser里面Submit code 你可以在这里面Submit code 比如说你直接点个run code 在这里面run实际上它还是一个REST API endpoint这个情况的话,它其实就可以用一些serverless node,比如说AWS的lambda这种serverless node,你实际上submitted的时候,你是submitted的时候的complete code的,你就是说不只是你自己的solution code,你把mate class的code一起submit过去了。所以这种情况下,这个server是完全不需要transtate的。这种情况下的话,你只要用这个API-GitP去verify你这个token,你不是想DDOS,你不是想abuse它的resource那你就可以只要验证了你确实是个Register user你就可以靠它的那个 serverlessserverless lambda去run这个code,然后verify input output,我想说的是这个其实不是最优解这个不是最右解,最右解的话应该是用web assembly,web assembly是一个最新的一个technology,它是一个standard,它是一个最新的standard,它是browser是支持WebAssembly,是直接在这个browser里面 run的,我们知道现在这个browser里面能 run的那个code只有HTTP 是吧 他可以 render HTML 可以browser 可以 render HTML CSS和JavaScript还有一些比如说 JavaScript 上面衍生的一些一些 codeWebAssembly是去年12月刚通过的,就是说它可以把你的其他codecompile 从 Web Assembly Code 然后直接 run 这个 Web Assembly Code实际上 Y Combinator 有个最新的 startup 最新的有一个 startup 就是专门做这个 in browser 的这个您可以再用的Browser作为IDE就是你所有的code呢就是写在browser里面写code的然后你brother里面写code呢,然后你可以用brother里面把它你的codecompile 成 web assembly,然后你的 browser 就 run web assembly,这样是最好的这样的话你就减少了,你就没有这个 additional cost,你就不需要去靠这个你减少一个REST API call 还减少你的server load 实际上你的browser就开始run了嗯对吧这个其实是比较新的一个technology,非常新的一个technology,就是去年年底才通过的,现在主流的brother可能最新的更新可能都支持webassembly的run了。这样的browser是不是很费内存,你如果看一下这个内存的话,你看一下这个Activity Monitor的话,你会你会留意到这个Chrome永远是非常在内存的。这个Chrome是非常非常在内存的,就是你可以看一下自己的这个Chrome是非常非常在内存的我们可以看一眼我这块chrome是占了353兆的内存chrome是非常占内存的on on on对好,我这块是作为一个衍生阅读吧,如果大家感兴趣的话可以读一下WebAssembly,这是非常新的一个protocol。好,然后当你的这个data much smaller compared to other services,这个data总体来说是个CPU-bounded,这个service总体来是CPU-bounded的。所以说我们这块其他的这个所有的relationship,所有的这个metadata management,就用一个user service就可以handle了。没有必要做一些非常细的micro service我个人觉得这个特别是你做这种非常小的service 蛮简单怎么样来你就只有个monorepo和monolis service 就足够了然后这个Compute Service的话是Heavy Lifting part,就是你Submit Code, Run Code的计划是比较重的部分
[20:00] 就是就是计划是你的不同的那个需要被不停的增加机器去optimize的地方这种情况下我们可以用一个WorkerPoolModel,这个也是之前讲过很多次,就是你过来的时候就是Asynchronize处理,你比如说你要run这个code,我先给你一个Recepe,SubmissionID,然后你可以不停的Poll submission ID,然后我什么时候执行完了这个code的话,我告诉你说这个执行完了。然后这样的话这个好处是什么呢当你是Asynchronized Processing的话你的Availability会提高这个我举过很多次例子就比如说你去新巴克点咖啡你可以说这个点咖啡的时候然后那个Serve咖啡的人直接把咖啡做好然后再还给你这是一种是吧或者是他给你个receive然后你过段时间去问一下他咖啡做好了没有然后再给你,如果他每次过来一个人他花五分钟时间去做好咖啡还给你的话,那它其实整个availability会很低,你有20个人就得等一个多20了,但如果它asynchronized处理的话,它这个availability会显著的提高。所以这样Asynchronize处理的话也是增加这个Litcode的这个网站的availability然后其次的话,我们就是这个网站呢,我个人觉得Litcode这块难点呢,是,呃,难点主要是被这个,这个就是,它整个data是没有难点的,CPU 帮的这块是没有难点的,但是它 security 是很大的一个难点,如果你真的是想去把 lit code 公当的话,我觉得不是很复杂的一件事,但是我自己没有事,我还是做一个好的good citizen,我是没有事的。但是我觉得如果你真是malicious,想把lead code供当的话,我觉得可能性不是太复杂。比如说他这个里面,首先为了security,首先你一定要put a limit on code size,你这个code不能超过,比如说不能超过10kb,10KB其实也很大了,或者计划的话我就简单定义不能超过20KB的,message size不能太大。然后其次的话其次的话,比如说你这个code run的时候,你不应该访问任何file,你不应该访问任何 file 你不应该访问任何 database 你不应该访问任何 network 和 socket当你访问这个的时候你就本身就有很大的security risk这是我觉得leadcode相对来说,如果我runleadcode的话,我觉得是比较难点的地方。但是你这种情况下你还是有一种方法可以去攻击这个Litcode网站,比如说你可以用一个zipbomb,就是你有一个压缩好的文件,当你解压缩的时候它size会几何倍的那个,比如说你压缩好只有一个k,但你解压缩的时候可能就两个t的size,两个terabyte size,这个是这个zipbomb的一个什么,如果你把这个zipbomb扣的,你可能不用它library,你就直接把这个code和解压缩的算法超过去然后你就zibomb一下然后反正Lead Code本身也需要把它的output显示给你嘛,所以如果它不限制它的output size的话,那你这个ZBomb它,其实我觉得效率也很高,是吧?毕竟它要把它output存下来,然后再返回给你。它可能tronk它的opputsize,但总体来说,我觉得Litcode的security check是比较复杂的一部分。是比较复杂的一部分然后这块的话,user service也可以broke down to micro service,但是现在的话就monolith service就比较好。然后有人问说micro service SOA有什么区别?SOA是一种agreement, service-oriented agreement更多的是一种谢谢大家更多的是一种就是你不同之间合作的时候哦它是一个protocol,是个agreement你知道吗,就是说你比如说你communicate的时候,你有一种agreement,像API一样,就是你定义好你的API,然后你们之间交流的时候,比如说你这个service之间交流的时候,你通过这个agreement来交流。对, service-oriented architectureService-oriented architecture. SOA是比较早的概念了,它很多时候绑定的是,比如说跟Java,Java 同一年代出现的,Java 和 Enterprise Software同一个年代出现的他很多时候,他很多时候就是,更多的时候是说,你怎么样有一个非常好的比如说你这个API design的时候你就是你是个REST API你REST API的话所有的REST API你都是就是一个resource或一个object是吧你定一个resource object然后你的REST API的话你的那个所有的action也是固定的比如说get post put 是吧,然后你当你进行这个,当你给这个第三方service或者internal一个啊Teams提供这个Service的时候,你就说你这个Resource应该怎么使用,你是不是有一个guide line,然后有个best example这种这个
[25:00] Purice 的话Micro Service的话跟这个不一样,Micro Service的话是跟SOA不一样,SOA的话很多时候是指的,因为它那个出现年代的话很多时候指的是monolith service,就是你deploy的,比如说像Southforce的话,有个Southforce是run到一个desk上的就说我在Southforce工作的时候,我们所有的Southforce,整个Southforce软件呢,你需要一个workstation来run的。它一起run的这种情况下,当你deployed production的时候,你就整个把Salesforce的软件deployed production上了。但是比如说你这个service使用的情况不一样,是吧?比如说你在某一个地方,比如说你get user或者user modify,你的request per second可能只有1k。但是你比如说你做一个transaction的request per second是一个million那你run的时候,deploy code的时候,你这两个codes同时deploy过去,但是它unplied code frequency是极其不一样的如果你做Micro Service的话,你可以就是把Transaction作为一个单独的Service,把它剥离出来。然后你这样的话,你这个Transaction Service,首先你这个Code Size会减少很多是吧,因为只有Transaction Service。co-size会减少很多 其次的话你这个你作为专门的一个team作为一个专门team的话,你可以专门maintain这个transaction。其次的话,你skill的时候,你这个transaction service也可以单独的skill。你不需要每台机器都有一个monolist的一个server,不需要每台机器都有个monolist server,然后起来说不仅支持你的transaction的request,你也支持user request,你可以专门做一个就是专门针对的一个transaction的这个这个transaction的service 然后只针对transaction request好所以如果你感兴趣更多的话,你可以搜更多的信息。这个Micro Service和Monolith Service有很多更详细的对比,你可以读几篇文章看到其中更多的区别。一般这个是不会作为一个不会作为一个就是专门考的考点来讲的,就是不会System Design的时候不会考这个,因为这个Monolysis和Micro Service呢,其实大家还是有不同的Preference,就是没有说是一个一定比另一个好的还是depends on the use case, depends on the data access pattern, depends on the data flow没有说有绝对的好,但是您可以看一下这两个明显的不同,Micro Service不同和Monolith Service不同,然后你需要有一些简单的understanding,好好 最后的话需要加一些Service Login Matrix Error Stack嗯login的话比如说你可以用一些promiseus然后加那个graphina是吧Login的话,比如说有很多第三方Service,比如说那个LogDNA啊什么,有好多第三方Service支持这个Login是吧。然后Metrics的话就Promisius加Graphana是吧,Aerostack的话,Uber是HealthLine嘛,就是都有很多,有很多那个Application你可以用的。这个Rollout的话,如果你的Design问题比较简单的话,你可以简单提一下,因为毕竟在日常生活中研发问题中,就是production的时候,rollout,service,maintenance是最复杂的一部分。其实比原始的code development更复杂。我个人觉得就是code development的话,比如说code development是花的时间,假设一个月的话,你这个mainten,rollout,还有backfixing,可能花三个月时间,这可能是占据正常developer时间最多的地方。如果有时间的话,你可以扫一下这个方面。好,然后这个API的话就相对比较简单了,我先停一下,就是这个architecture带有什么疑问吗?会有什么观点,不同的观点,或者觉得这个哪一块儿,不明解或者是觉得哪块有问题可以直接说就是直接说如果有问题的话Hello Scott, 您说, 还有一个问题, 就是你在讲, 就等user他submit了一个, 呃,就是query之后呢然后相当于会它会constant pull然后去看这个submit的结果所以说它在短时期内会产生很多的API call就这块一般是怎么handle的是用cache吗还是有什么其他的办法不用cache啊这块没有必要用cache的因为你用cache的话你的result肯定是就是有learnetency的或者那个什么的,并且用开始增加了unnecessary复杂度。这块用什么呢?就是您可以做几种方式,一个是你可以,像这个Litcode的话,你实际上这个client呢,你可以就是你这个Pol的frequency可以自己configure嘛,比如说你submit了以后你就15秒或者是30秒去Pull一次这个其实就无所谓了是吧除非你user自己手动的去Pull这个result那这种情况下user
[30:00] 手动Pow的话你应该return最新的结果是吧如果不是的话你就15秒30秒Pow一次然后其次的话你可以做那种就是那种啊就是push model,push model有很多比如说用web socket啊这种然后有一些老的比如说Long Polling这种是吧,Long Polling或WebSocket就可以,就是Client端不去push,不去不去泡 server 端而 server 端好的时候 notify 去看的 比如说 web socket 和 long polling 这几个 mechanism好的 感谢好的 大家有什么其他问题吗好如果没有的话我们接着看啊这边的话就是问就是这块API的话相对比较简单,我觉得这个Leadcode总体来说跟YouTube比就是简单很多,YouTube前天我花了好几个小时,Leadcode这个我可能写了一个小时多就写完了。YouTube那个可能前天后来大概写了四五个小时我觉得它中间还有很多复杂的地方,如果大家感兴趣的话可以再回看一下YouTube那个视频,我觉得还是很有趣的地方。YouTube还有很多很有趣的地方。好,这个的话就比如说你可以getLitcode problems,然后你给一个user session,一个user token和session ID。不同 session 的话这个 problem 可能 mark 的不一样是吧然后你就显示 problem ID 然后 problem title 和这个 marker 是到底之前做过还是没有做过然后另一个的话就是 submit endpoint嗯上面的end point的话就比如说user token,problem id,code,language id和session id,这里面的话你这个timestamp是在server generator,所以你肯定不会从这个API这块submit。然后当你的Code submitted以后,你会return一个submissionID,然后你就可以hold这个result,然后看一下你最新submission的result。然后在internally,在这个serverinternally,你可能会要把这个saucecode的,就是当你把这个saucecode的,不管是比如说C++还是Java,当你把它交过去的时候,它首先是个文本。然后你需要compile这些 code如果是compile的language的话你可能compile code如果是interpret language的话interpretation language比如说python的话你就直接run就可以了不管你是Compile language 还是Interpret language 你就需要不停地执行N次 是吧?这个N是和你的这个test case相关的然后你把这个Result output呢和你的Crack output进行对比因为我记得这个LitCode是short circuit的,就是只要第一个不一样的时候,它就return,这个result是run,这个code是run,这样可以节省很多时间,因为大部分我不知道平均通过率多少,但是我自己的话是可能有60%的通过率。就是40%的code 是上交的时候是run的,就是,就是,所以这样的话可以至少能节省一半的这个一半以上的这个 unnecessary result trap就可以short circuit一下然后这个run的话再次说一定要cap到200毫秒和200MB实际上的话我看它Litcode是50MB,我们就说50MB,然后你需要额外的Security check,这个Security check我总觉得还是比较复杂的一部分,我觉得如果SUM的话就是你不能访问任何Resource你可以暂用CPU,你可以暂用memory,但你CPU和memory就是时间是固定死的,但你不能访问任何resource。然后其次的话这个code是一定要run在docker里面的因为这个docker里面如果你这个docker有毒是吧你这个crush掉了然后这个你可以有一些Docker Orchestration Service比如Kubernetes可以 bring up一个新的Docker node,所以你这个Docker挂掉挂掉了,所有这个Hairly lifting所有这个Compute node, Heavy Lifting,都是Sign and Forget,Sign and Forget的意思就是说它如果挂掉就挂掉了,如果有需要的话,我们可以兴起一个,就是兴起一个Compute,或者兴起一个新的Worker,就是Compute Service。那之前挂掉的话,因为我们现在早不见这个Submission,这Submission就死掉了,那我们就说可以,不管是Return Internal Error,还是Return什么Error,反正Return一个Error就可以了。我记得Litcode早些年的时候,我上次用Litcode三年前,还是有很多这种internal error,经常就是submit以后就遇见一个internal error,要求我重新submit,这种可能就属于server挂掉了。谢谢大家这个也是就是加一些better isolation,就是当你比如说当你这个Docker Node挂掉了以后,你不应该影响其他的是吧,比如说我觉得这个Docker Node的话,这个Docker CPU的Size和这个MemorySize还是需要非常carefully orchestrate it,
[35:00] 你肯定是一个 multi-tenant的一个 docker,不可能一个 docker只 serve 一个 request你这个overhead太大,就是你新建一个docker的overhead太大,你肯定是monit tenant。但是你这个monit tenant如果太大的话,你docker cpu size和memory size太大的话,你一个program,一个session run的时候会领想另一个session的performance。所以这样也不太好,所以这个可能他需要不停地做然后决定一下具体是什么样的Docker的这个CPU数量啊MemorySets是比较符合它这个Performance就是CodeEfficient是最高的我们看到过其实这个按这个之前这个数量估计的话,它其实只要三台机器就可以了,并且这三台机器不是说为了handle这个heavy load,更多是如果其中有一台机器到的话,就是提供一些Aero的荣誉是吧?提供一些荣誉就够了所以整个这个cost其实整个这个least code cost其实很低的它更多是一种content cost就是比如说初心提的时候怎么样提更有质量这种content cost好其次的话,您可以有guess submission,是吧?这里面problem就是您可以根据一个IDguess submission,也可以根据所有的这个,就是所有的 submission 来 get submission嗯根据你自己过去所有的submission来getsubmission然后最后的话是getRuntimeDistribution比如说这个就是我们这个Runtime花了多久然后打败了多少的用户这种谢谢大家啊好,这个 API嗯就这样子了然后大家有什么问题吗这块可能还有一个就是更简单就是get problem get single problem就是我这块没有写然后这个就是detail的这个data model我也没有写很细啊,因为这个我觉得跟我风格有关,就是这个我觉得是比较tds的work,其实没有什么难点,就当然比如说你要get problem,给一个user token,给一个problem id,get problem的话,自己也可以handle掉,就是他怎么样的data结构里面要说fill的,这些都可以自己handle掉,我这块没有练很细啊。好,这个API这款大家有什么疑问吗?而Edith说,如果按memory limit应该是 language based, Python 可以很大的 memory, Java 的话,250 megabytes 基本就很大。就是吧, memory limit exceeded.然后是否考虑需要discussion部分啊,我这块是没有考虑discussion和comments的啊,为什么呢?因为在那个YouTube那个视频里面有专门一个session怎么样讲community,然后discussion,就是上周,上周三啊上面有讲那个 discussion 和 community 我觉得是非常重复的内容 我觉得没有必要去讲重复内容好 如果没有问题的话我们看最后的database这就是最后一部分了好Database 首先有个 user table,然后这个 user table 肯定用 SQL 我觉得说 user table 用 SQL 应该是没有什么问题,除非这个User Table设计的有问题啊,我觉得用Useql的话肯定是比较来说比较约定输送的东西了有个user uoid 然后有个username 然后有creation date,password是用hash的,password是一定要用hash text的,就是你不能存密码的,否则的话你security会有问题。这也是design中的一个red flag就是你password如果用明码存的话是一个非常大的red flag然后有个Membership Expiration Date 这个是如果你是有Member的话是这样子然后你有Credit Card,Payment,是吧,Payment也可以单独做出来,做一个单独的Table因为你一个人可能有多个payment,可能做一个单独table,然后还有一些additional metadata,比如说location,github,link,link,link,这种我就不列那么细了。然后其次的话,这块需要有个session table,我这块好像是可以自己定义的,比如说我这块就create了一个,Create 了一个 Java Session 是吧?然后还有一个 Session 是有个 Go Session,就是你可以create 一个 Session Table然后最后的话是有个submission table嗯Submission Table是这个里面我觉得相对来说从Data角度比较复杂的一部分,我们注意到一点就是SQL的Rho Size是8个KB的,就是我查了一下就是SQL的Rho Size是8KB的,所以这个Code呢,直观感觉这个Code是不能直接存在这个SQL里面。然后这个code可以存在两个地方,一个是存在Document Database,因为MongoDB的Document Size 16MB所以这个code是可以存在mongo里面,或者是存在一个,这个code也可以存在哪里,也可以存在一个object storage,比如说amlon,s3这种地方也存在去也可以。但是这个code,就是可能会有一个solution,说是你把这个code,
[40:00] 整个这个table,整个这三mission table 存在mongo里面然后把这个code也存到Mongo里面,因为毕竟Mongo的这个Document size比较大我觉得这个不是一个好的solution为什么呢?因为这个里面这个submission这个state是要被反复更改过几次的包括你这个runtime和memoryconsumption是反复更改过几次的如果你把code和这两个放在一起的话,特别这两个需要更改过一两次的放在一起的话你每次更改的时候你实际上是读取整个大的几个MB的Json然后modify一些,然后再把它写回去,实际上每次modify的时候,每次modify是document,就是granularity在document上的。所以你这个code其实反复被写了两遍就虽然你只改了比如说你这块只把state从submitted变成running但你这个code是反复读了一遍又写了一遍的总体来说,如果你想优化更多的话,这个不是一个很好的选择嗯但是如果以这个lead code的这三密审量的话,final9也不是一个很大的red flag,是一个yellow flag,不是一个很大的red flag然后最后的话这个State的话和Runtime Matrix, Runtime就是表示你这个Code run了多久,然后你consume了多少memory,然后这个state的话可以是submitted当你 submit code 的时候,然后 queue 到那里就 submit it然后当这个有一个worker pick up 你的 code 的时候就 running然后当成功是success或者是error,然后user应该可以about it,有个user about it operation。或者是你这个worker node直接就down掉了是吧,你找不见这个submission了,你也可以把它变成有个background process,把它变成about it然后最后的话,这个RuntimeStates,RuntimeStatuses,Statistics就是你看到这个Data呢,Runtime Statistic Data 应该有另一个Process generated, 它可以读下所有的Submission对于同一个Problem对同一个problem同一个language所有submission然后把它简单统计下,然后做成一个非常简单的一个,一个一个就是那个直方图,然后,然后跟你现在的三 mission在一个脂肪处的位置然后把它显示出来应该有另一个就是这个process处理,这个是不需要real-time 的。不需要real time如果是需要real time的话有一些case比如说这个trending什么real time啊比如说假设leetcode有个这个trending runtime比如说Lead Code Context有个Trending Runtime的话,你可以把这个说的这个submission放在一个Kafka Topic里面,然后你可以用Flinkflink 处理一下这个 runtime,叫你有个 trending runtime,或者是 rolling window runtime但是实际上大部分的时候都不是不需要那个有 runtime 的好,我们计划有几个问题啊第一个问题说IDA说为什么user table不用non-sql呢?这个可能是和之前讨论有关,就是就是这个我觉得虽然是说我个人的preference 但我觉得也是业界的共识就是 Seql 优化了很多东西如果你能用 Seql 的时候任何情况下都应该优先用 Seql 用 non-Seql 会给你造成很多不必要的麻烦除非你有很strong的 reason,比如说这种情况下,这个code可能是个几十k,20k,30k,是吧?就举个例子,20k,30k那你放到这个SQL里面的话,它有Row Size Limit,你可能就不适合放SQL,并且这个Code的读取都是K-Value的读取,是吧,就不适合放SQL,除非你有Strong Racer,否则的话,尽量能用SQL的时候尽量用SQL,特别是这种这种所有的data都不是很大,并且这个well understood question,用SQL可以解决很多很多麻烦。好你可以认为 SQL 是 no-brainer,大部分是 no-brainer,当你用 no-sql 的时候,你需要 justify 你的 choice一般来说但是在这个也是另说的就是在不同公司也不一样,比如说在Uber里面,如果你有MySQL的话,MySQL他那块很明确的说,MySQL当他做这个leader election的时候,他是有availability会有影响,他会有200毫秒的。200毫秒的这个就是on response,所以他availability在那个leader election的时候会有on response time,所以它availability会比其他的service其他database choice的availability的低谢谢大家所以那种情况下的话,你可能说我为了保证我这availability是4个9还是5个9的话,我可能要不用这一口,这也是一个valid point。然后code ID是否应该是code pass,code file pass,这个的话我不建议直接把它存到filesystem里面,就是code不建议直接存到filesystem里面。我们之前就是讨论过就是filesystem说你这个file可能是coopted的,你还是把它存到一个signal里面你或者是用amlone s3 guarantee 你这个data object是不会crafted或者是用DocumentDB,也是guarantee你这个data是boycrafted是不建议把这个就是直接存到
[45:00] 还是用一个ID或者Document Reference,Mongodb叫Document Reference好然后 Mike 说每个 submission 是不是就一个 record 有一个 ID改了重新summit的应该成一个新的吧?对,这个summission是当你summit的时候,当你clicksummit的时候就给你generate一个summissionID这个就变成immutable了,就这个submission是不变了你不小心多click两个,你是两个submission,那你应该有两个submission ID。谢谢大家谢谢大家谢谢大家还有一个说是感觉这个user和其他表没有什么transaction,可以像之前一样做成noSQL。这样 payment 可以做成 fieldType 是 payment array 叫Payment Array,就是用SQL也是可以支持Array的,现在这个SQL也是支持进行Array的,就是不是说SQL不支持Array的,就是SQL的Field也是支持Array的,您可以支持JSON,放个JSON也可以。SQL和NoSQL还是这样,当你用NoSQL的时候,你需要justify your choice,就是说你不管是它 data size 不行啊,还是它有各种各样的原因啊,或者说它这个比如说它 response availability 比较低啊,或者 response 比较慢啊,你需要 justify your choice,但是一般来说,当你没有一个 strong reason use no single 的话,我个人觉得这是我个人的choice,同时我觉得也是基本上我见过所有的就是system design,就是interviewer的一个choice,就是尽量用SQL,因为SQL毕竟还是稳定一些。然后静于说,lead code正在edit code是放在哪里?那里的code被改的频率应该很高你edit code就在browser里面比如说你在这改code的时候你的code是这样子在browser里面你brother就是一个client嘛,当你在这idea的时候,你就是在brother里面。当你只有当你在submit的时候,你会做一个API call,比如说你在这ID的时候,不管是加等什么的,就在brother里面,就是承认的code。谢谢大家然后请问一下Seql为什么在Leader election的时间比较长因为Leader election是要做consensus当你做leader election的时候,我们会在周四的时候讲很多基础的东西。leader election是你要做consensus的时候。然后consensus的话,常有的比如说就是,不管是raft,最近流行的raft,还是之前的paxels,它整个系统复杂度是非常高的。你需要几个coordinate,你需要communicate,所以这个leader election时间是肯定要比较长的。这所以这个Leader election时间是肯定比较长的,它不像一个简单的Database write,它时间可能就几毫秒或者是几毫秒之下。所以我想问一下那user表就没有做replication是吗我们这块说过,你其实可以做Copy吗?就是SlaveCopy,做一份Copy就可以了。所以他们是一步步伏制一步复制线,Asynchronize,因为这个database的盗鸟的概率太低,你Asynchronize复制就可以。谢谢大家谢谢大家基本上所有的 service 都不能只有一个 single node 因为只有一个 single node 当你一个 service 当掉的时候就 unavailable 了这里面的话我们看Stateful ServiceStateForServiceGl SQL StateFolderwork queue 理论上是state fault 但是你实际上submit一个work 你当地也无所谓 你就直接说servererror就行了这里面其实只有secret state fault 然后你的api user token是state fault但你这个token也是可以丢的,当你这个node当鸟,这node的当鸟概率非常非常低,就比如说100天当鸟一次,你当鸟的话你就让user,fals user,relogin就可以了。其实这里面只有SQL是Stateful,你说这个User Service都是Stateless,你就可以十遍加你随便加,比如说你处理不过来了,或者Compute Service处理不过来,可以随便加。好多问题啊今天我们看一下有时候,user多次click的时候,submit的时候会submit太快了,这个fature怎么实践呢?这肯定是在client短时间,你比如说submit了以后加一个那个加一个那个wait time,就是你看一下当前时间,记录一下当前时间,然后你下一次click的时候对比一下上一次click的时间如果这个时间超过几秒钟,你就说click太快了,就在看了一段就可以实践。好然后还有说重新login的时候,正在edit code好像在一周内会restort重新login的时候做的end code,那这种情况下,如果你是这种情况下的话,你的这个,它可能做了一些optimization,就是你的code它可能会Pure Articles save下你的code所以它会有一个API-Code到backend把这个code save下来在看上去做了的就跟静怡说的一样,就是你设计的Code logout 回来以后,还可以看到Edit一半的Code,
[50:00] 比如说Gmail传一遍,Gmail传一遍,这是一个User Experience Optimization然后对3MediaCode需要做Serialization吗?还是直接String存进Table?你肯定要做,Serialization是肯定要做的,你从你这块,就是当你transfer你的code从client端到server端的时候,你肯定要做Serialization/Desserialization我觉得你这块应该说是compress吧,你是不是要这个compression可做可不做,如果您可以做一下实验,就是bitcode有data可以做一下实验,说compress的话,它能节省很多space的话,是可以做compression的。但是我觉得它是个CPU-bonded 所以没必要做就是说你加compress和decompress 你是用那个时间换空间嘛,你说白了是减少空间吗?但是它是CPU bonded的话,本来这个CPU就够忙的话,我觉得可能没必要好宣溟 存历史 存 historical submission 的话我觉得用Cassandra做submissionID作为columnKid,然后在后台batch 合并为一起,用 Cassandra 也可以,这个 field 这个 table 用 Cassandra Submission 也可以,我觉得 Cassandra 也是一个 valid choice嗯并且用Cassandra的话,你这个code update的时候,第二次update的时候是不需要modify它的,就是Cassandra是个不错的 choice,确实。你需要想一下你的partition key和sort key,但是当你进行Katandra,就是你第一次存储,你update的时候,你可以只update后面几个column。没必要update这个code就是没必要updatecode不一起update 不帮帮到update是可以的谢谢大家谢谢大家增量编译有没有办法实践?增量编译Liu,你能解释下什么是增量变异吗?谢谢大家谢谢大家中量变异incremental compile我没有听说过Increant Contal Compile的问题,我还是学过一点Compiler的课,也做过一些Compiler的优化,但我没听过Increant Contal Compile。incrementalcompal我没有听说过啊你如果在的话能解释一下啊好,没有submit code在logout,还能看到之前edded一半的code,有可能是在session里面存了,你换个browser就看不到,这也是有可能的。就是它可能是存在后段,有可能是在browser里面就是进了一些响亮的优化,有可能。之前讨论过的comments和discussion是否可以考虑noSQL?在后端的话,请问如何和 SQL 表提供数据给前台,如何考虑 single page load?comments和 discussion 可以看一下之前的 code,就是之前的讨论。在YouTube里面讨论过一个comments和discussion,然后在Design Slack里面也讨论过一个comments和discussion,这里面其实是这个data是有不同的优化过的。我记得在slack里面,我当时propose的是用danymode的,就是这个slack conversation, discussion show DynamoDemYouTube我忘了YouTube是什么,可能是用MySQL吧,但是你用Denymal也可以的,是可以考虑用NoSQL的确实。好,最后的话就是Problem Table了,在Problem Table相对比较简单,你需要一个Problem ID,然后需要一个Creator,Creation time, 有个title, 有个description这个Description 因为它量还是比较大的,其实这个其实挺大的。然后你可能需要另外有需要一个IOID和一个additional data是吧,metadata,比如说有多少个submitted,有多少个accepted,然后你这个submitted,accepted,如果是需要实施的话,你可能还是需要一个kafka和一个和一个flink 啊这样的话你比如说有实时性那种你可能需要这种realtime specular state然后结合一下过去的这个这个可能需要这两个然后这里面Description ID的话,你可能需要支持一些Multimedia,比如说有个Image什么的,你可以把Image存在一些存在我还真不知道他image是哪儿,我直观想想的话可能能存在一个resource里面,比如说AMLON S3这种,或者是存在一个filesystem里面。把 image 成为一个 file system 成为一个 image file谢谢大家但是不管怎么说这个DescriptionID这个descripient是比较大的 和这个code处理方式是一样的input和output file,input和output file,code和problem description在YAM2NetDocumentDatabase,YAM2NetObjectDatabase里面这个应该是就是不要存在这个relational database 里面 因为它毕竟size比较大一点然后它读的那个pattern也比较简单 就是一个read 一个write一个read,一个read,就是根据K来读
[55:00] 有的这个fetch 也比较简单LeadCode就相对来说就设计完了,不是太复杂,大家可以思考一下最后看一下这个问题,然后有什么额外的问题,再给几分钟时间内有什么额外的问题。谢谢大家有个人说Submission是NoSQL表吗?Submission可以用SQL,也可以用NoSQL,NoSQL的话,我觉得刚才有同学说DenimalDB是一个不错的选择,Denimal是一个不错的选择,SQL也可以,SQL的话你只要把code reference 到另一个data storage就可以谢谢大家请问会员过期类似部分需要考虑吗?会员过期的类似部分谢谢大家这个没有什么复杂的吧,就是你比如说你你当你呃Charge 的时候就是当你当你就是你有 payment 的时候你就把这个 expiration date 换成一个时间反正这个表示你自己定的,你随便定一个时间,你可以定的永远不expire。或者定了多久以后X bar然后它这个transaction,payment transaction通过了以后,就set expiration date当你这个XPAR 可能有个 auto charge 是吧, auto refresh 是吧或者是Authersubscription 是吧然后如果是yes的话到时候就再查一遍然后再把你这个ExperationDate然后再refresh一下如果是 no 的话,你到时候可能就是过了这个Membership expiration date的话,你就不是Member了,这个处理相对比较简单。好好好好,今天就讲到这里,然后我会,就是周四的时候吧,周四的时候我会就是征求大家看有谁想感兴趣,可能找两位同学啊,找两位同学,然后下周面试一个比较简单的一个System Design,然后我们就是,尝试一些面试的过程,找两个volunteer然后我会另找时间我看已经有一个volunteer了,我会另早时间,然后就是单独的,我们先就是花半个小时,然后问一个问题,然后讨论一下,然后录两次,然后我们明天的时候就讲这个讲这个就是被interview的这个,看一下实战的,interview的实战啊,就跟打敲拍一样,一边要学理论一边要搞实战嘛,就是这个实战还是很重要的。System Design 实在是很重要的。到时候就是练习一下,我到时候在群里面再问一下,就是优先报名两个人,我看Warrant已经报名了,再找一位同学。好然后周四的话,我想周四讲什么,我给你看一下周四讲什么。中四的帐篷谢谢观看谢谢大家哦,周四不在这里面,周四讲database的存储。我们会讲一下,一个讲一下Btree,讲一个Btree,然后讲一个LogStructureTree。然后再讲一下那个Analytic Database和Transactional Database的不同,还是有一些很有趣的地方的,然后大家感兴趣还过来参加一下。好,今天就到这里了,谢谢大家。谢谢大家谢谢大家。