关于如何设计google calendar

之前面试的时候有被问到这个题目,自己也在网上查了相关的题解,这里是我整理到的东西,不知道除了这些还需要注意什么,老师能不能出一个文本课件说一说这种类型的题目。因为看面筋里,这题目有点像OOD,稍微画了个简单的图,但是肯定漏了好多东西,有点没有思路。

Google Calendar

-



API的话,我找的是google自己的API:

点评两点:

  1. Google Calendar 除了你提到的功能以外,安排 Recurring meeting 是比较有意思的,可以想一想怎么在数据库当中存这些 Recurring Meeting.
  2. 系统设计图当中 Kafka 的目的是什么?用户不能够直接 Consume Kafka event.

我想法是用个queue去帮助用户handle 多个的event,然后一件一件发送给用户。不知道这个想法对不对,有没有比较正确的处理方式呢? 谢谢!

对于老师提到的Recurring meeting,我之前还真没有想到怎么做,除了在数据库中将event/meeting加一个column来判断是不是recurring meeting,然后如果是的话,就要让event handler处理以外,还需要注意什么呢?然后如何在面试中表达出来,或者画出来呢?我感觉现在这个能力我比较欠缺。谢谢老师!

Kafka 是系统内部的组件,不能直接用跟用户沟通。用户跟后端联系都要通过 Gateway 进行。这里如果是发送 push notification 的话,我们通过 Apple, Google 的 API 是实现就可以了,不需要 Kafka。读取 Event 的话,用户主动向 Event Service 读取。

Recurring meeting 的难点在于如何快速读取 Calendar。比如我们想知道 1/1 1pm 有什么会,去读取历史上所有的 Recurring meeting 然后再计算这个 meeting 会不会在这个时间出现就不太合适了,因为读取操作太麻烦。

因此,我们不仅需要在数据库当中存储每一个 meeting(所有的 occurrence 算同一个 meeting),我们还需要存 meeting occurrences。我们提前计算一定时间范围内的 meeting occurrences,存储好,读取的时候不需要再计算了。

老师,我对calender设计也有几个问题。

  1. 定时的push notification如何实现呢?是通过schedule event的时候就放入message queue 吗?message queue可以支持很久的delay message吗?比如1个月。之前在网上看到一个人设计用message queue去schdule这些notification,然后一个server去接收然后send notification给用户我有点不解感觉message queue应该不是这么用的?
    我想的另一种方案就是后台run 一个cron job去不断的scan db table但是这样的话会不会db压力比较大?没有这方面的经验所以不知道怎么实现实际一些。

  2. 关于recurring meeting, 老师之前的回答是存储好一定时间的occurrence,我的理解是当schedule meeting的时候就把每一次的recurrence当成一个新的meeting存到数据库里?不知道这样理解对吗?

提前谢谢老师!

  1. 我会采用 Cron Job。需要有定时的 Async Job 来读取数据库当中的信息然后发送 notification。读取数据库的时候只要读取某个时间段的信息即可,不用 Scan 整个 Table (前提是在 meeting start time 上加 Index)。Message Queue 的方案正如你所说,并不合理。

  2. 正确

这个问题如果需要加room的话,要处理room上的concurrency是不是就在room table里那个room的row上加个锁呢?
A需要book room 1的7:00-8:00, B需要book room1的7:30-8:30 (他俩是同时book的,在想book的时候这个room是未被占用)

但是这样加了锁又阻塞了其他book请求,比如C要book 9:00-10:00,本来不冲突
总不能room + 分钟上锁吧

每个 room 层面加锁已经完全够用了,不会同时有很高的 QPS 去 book 同一个房间。即使是时间上不冲突,我们也保证定同一个房间需要一个一个来。

您好,我感觉平常大家对于recurrent meeting更会倾向于选择具体的weekday,所以可以用两个database一个存onetime meeting另一个存recurrent meeting,这样对于recur meeting我可以以event去存而不用给每一个occurrance写一次。然后用一个scanner(notification server)根据当前时间戳扫描某个时间后(比如15min)之后即将开始的会议,向user push notification。但是有几个问题想请教一下老师。。

  1. 请问老师在楼上说的在meeting start time 上加index 能稍微解释一下吗?感觉本质上就是筛选出15min之后要开始的meeting id?
  2. notification server从数据库中读数据的时候应该是以每秒为间隔读取吗?这样数据库的读操作压力会不会比较大?我在task scheduler的系统设计中也看到过每秒从数据库中读取未执行的文件的设计,不知道这是不是一个可行的操作

谢谢!

即使有两个 table,还是建议把 recurring meeting 提前算好,变成一个个单独的meeting,读取时候会更高效。

  1. 是的。可以更高效地找到两个时间之间的所有的会,不需要遍历。
  2. 可以想象成所有需要发送notification的会议都已经排队排好了,每秒读取的时候就从队列的头上读取出来看一下是不是到时间了,到了就执行并往下读,没到就等。不会压力太大。

老师 打扰了,最近遇到了类似的calendar设计问题,但是有需求: User可以创event邀请其他人,收到的人可以接受/拒绝, 在自己的calenda‍‍‌‌‌‌‍‌‌‌‌‌‌‌‍‍‍‍‌r可以看到自己创的和受邀请的event. 老师您觉得如果加上这些需求,设计的时候应该需要注意什么呢?

需要做一个数据库设计,对于每一个 event 不再是存参加者,而是存所有被邀请者,以及每个被邀请者的接受/拒绝状态

老师这里如果更改event table是不是冗余太多了,增加一个新的invitee status table是不是好一些。
因为其实event本身也是有status,是不是被cancel了 ,如果再加上invitee的status是不是太复杂。
我自己做的一点table的设计

是的,如果用 relational db 来 model,invitee status 分表比较清楚。

因为使用了sql db,join的latency可能会长,是否可以考虑denormalize+fanout?denormalize是把需要给每个invitee发送的data (所有这个user应该收到的一个list of calendar event)提前做好,user pull的时候或者直接push给user。fanout是因为一个calendar event会有很多invitee,需要复制多份给每个invitee。

有必要这么做吗?不这么做的原因我认为是1) 一个会也不会有太多人参加,不像twitter follower那么多 2) calendar应该是以push 为主,latency从DB join table读信息也可以接受 ,(不user pull的时候肯定期待很快返回data)。

另外是不是不太需要cache?毕竟每个人要看到的data只有自己看,不太会很多人读同样的data。

我倒是觉得如果读取的时候latency太大,可以考虑为每个人有自己独立的Calendar,提前做好。因为会议人数不会太多,独立Calendar,利大于弊。

recurring meeting的case,如果要create所有的instance,那么在用户create一个recurring meeting的时候,我们要同时创建所有的instance么?如果synchronous地去创建,感觉不靠谱,会影响write操作的latency。可是如果asynchronous去创建不同instance的话,感觉可能会有consistency的问题。比如,用户创建了recurring meeting,立即刷新calendar,翻到下周,结果发现meeting还没有出现。这个要怎么解决呀?

我猜client有logic保证刚创建的recurring meeting是存在client的。

最近正好考到这个,我自己想的比较全但是不少点当时没要求(比如rurring, booking,modify, saga)也没时间写。把丑图贴出来,不知道这个design有明显的问题吗?

可以 sync 创建一个月里的 instance,之后每天定时去创建一个月之后的新的 instance, 保证有一个月的 window 是创建好的(这也是读取最多的)。然后在读取的时候检测一下读取的时间范围是不是在一个月以内,如果不在,就根据 recurring meeting 当场读取给用户。

最好不要让客户端承担这些逻辑

Invitee service 我觉得可以跟 event service 合并了,而且存储的时候 invitee 和 inviter 可以都存一块,变成 User table,就是存每个用户有哪些会的表。