learn-tech/专栏/高并发系统实战课/答疑课堂思考题答案(一).md
2024-10-16 11:38:31 +08:00

151 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

因收到Google相关通知网站将会择期关闭。相关通知内容
答疑课堂 思考题答案(一)
你好,我是编辑小新。
今天是一节答疑课。我们的专栏已经步入尾声。除了紧跟更新节奏的第一批同学,也很开心看到有更多新朋友加入到这个专栏的学习中。
很多同学的留言也是这门课的亮丽风景,给专栏增色了不少。大部分的疑问,老师都在留言区里做了回复,期待更多同学在留言区里分享经验,提出问题或尝试解答他人的疑问,我们来共建一个共同学习、积极交流的良好氛围。
为了给你留下足够的思考和研究的时间,我们选择用加餐的方式,公布每节课的参考答案,也会精选一些优秀同学的答案展示出来。这里要提醒一下,建议你先做了自己的思考后,再核对答案。另外每节课都有超链接,方便你跳转回顾。
第一节课
Q请你思考一下用户邀请其他用户注册的记录属于历史记录还是关系记录
A用户邀请其他用户注册的记录我认为属于关系记录。
虽然这种记录有历史记录特征但是被邀请注册的用户只能被邀请一次所以总量是可控的。同时这种表的用途很明确表内记录的是关系记录查询时会按邀请人或被邀请人uid进行查询。
留言区里也有不少精彩的答案,推荐你去看看。比如@移横为固的答案,这里我也复制过来:
一开始觉得注册邀请表应该作为历史表。思考了下作为关系表也是可以的。
在满足下面的注册邀请前提下:
1.邀请人用类似二维码分享方式,注册人主动扫码注册(不使用点对点邀请,被邀请人可能不接受)。
2.只能注册成功一次。-
这样每一条邀请记录都是一个用户的注册记录:可以定义如下字段:(邀请者,注册人,注册时间,邀请方式)。-
表的字段结构都非常简单,记录的总量最多就是账号量,并不会随时间不断膨胀。因此可以胜任关系表的查询需求。
在实际项目中,我们会遇到很多类似情况,需要我们预防超出预期的操作,核心在于我们怎么约束使用表的人,以及我们要怎么用表里的数据。
第二节课
Q1使用BloomFilter识别热点key时有时会识别失误进而导致数据没有找到那么如何避免这种情况呢
A1有一个特殊方法能降低概率原始key通过BloomFilter 检测一次md5后再通过另外一个BloomFilter再测一次。
Q2使用BloomFilter只能添加新key不能删除某一个key如果想更好地更新维护有什么其他方式吗
A2请参考Redis的Cuckoo Filter的实现。
第三节课
Q用户如果更换了昵称如何快速更换token中保存的用户昵称呢
A在更换用户昵称同时更换修改端的token。如果我们的用户有多个客户端那么可以利用缓存更新提及的Version版本号让客户端定期检测判断token是否需要更换。
对于这个问题,置顶留言里@徐曙辉同学的回答也很有趣
如果我来做快速更换昵称的功能,有两种方式:
a.在用户修改昵称后内存中加入一个用户标识解析token后读取该标识有则返回特定code让客户端重新拿token。甚至可以不用客户端参与返回301重定向到获取新token的路由。
b. token里面不存用户信息只存用户ID需要用户信息的时候从缓存读。
徐同学的第一个解法很暴力,但是很有趣。
第二个方式也很有意思,这里我也补一个应用技巧:我们可以通过设定固定网址 user/用户uid/heaer.jpg方式直接获取用户头像这样也不用考虑更新问题了。
围绕着我的补充,这个话题还有后续讨论,我也一并展示出来,仍然是徐同学的回答:
按这样做头像可以http://xx.com/user/用户ID/header.jpg静态文件可以因为反正都是远程http渲染。但是昵称和其他信息都这样处理每一项都放到远程地址性能不是很好是不是可以http://xxx.com/user/用户ID/info.json再反序列化呢
这样确定是占了额外的存储空间优点是不用查DB和缓存减少它们的压力在Web应用中用户信息读取挺频繁。
我认为这个思路很优秀,建议尽量使用对象存储做。关于对象存储的话题,你还可以参考第二十一节课的内容,我在里面详细分享了对象存储如何管理小文件和大文本。
第四节课
Q如果 Otter 同步的链路是环形的,那么如何保证数据不会一直循环同步下去?
AOtter在事务头尾插入同步标识解析时会通过这个方式防止发起方再执行同样事务。
第五节课
Q请你思考一下为什么Raft集群成员增减需要特殊去做
A这是一个复杂的话题核心在于增减成员在加入后需要同步数据并且会参与竞选。我觉得后面这篇文章分析得相对完整你可以点击这里查看原文。
第六节课
Q这节课中的有些概念与 DDD 是重合的,但是仍有一些细小的差异,请你对比一下 MVC 三层方式和 DDD 实现的差异。
A这个问题没有标准答案。我们结合同学的回答一起看看。
@Geek_994f3b同学的回答是这样的
我个人觉得两者只是作用域范围不同从程序的角度看MVC模式用在线程间(单体应用)而DDD用在进程间(微服务)那么MVC + RPC协议 + 业务拆分 ≈ DDD(个人愚见:),像是在单体上多套了一层。
@徐曙辉同学的回答是这样的
MVC是项目目录功能分层设计偏框架而DDD更多是业务实体领域和彼此之间的关系偏业务。
再补充一下我的想法建议结合贫血模型和充血模型区别以及领域模型和Service的区别来考虑这个问题。
第七节课
Q1请你思考一下通过原子操作+拆开库存方式实现库存方案时如何减少库存为0 后接口缓慢的问题?
A1我们可以再设置一个key标注还有哪些key有库存。
Q2我们这节课的内容并不仅仅在讲库存还包含了大量可实现的锁的使用方式请你分享一些实践过程中常见但不容易被发现的精妙设计。
A2这道题没有标准答案希望你做一个有心人在实践中多多关注各种锁的有趣设计。
第八节课
Q用什么方法能够周期检查出两个系统之间不同步的数据
A在数据上增加修改时间或版本号每次更新的时候同步更新版本号通过版本号能够很好地帮助我们识别哪个数据是最新的。
我们再看看@LecKeyt同学的回答
每条数据都有唯一的数据标识一般是自增id或者有规律一串数字唯一id而且一般都是小到大根据这个最大值应该就能判断出来。如果数据不同步应该找到对应数据节点做补偿操作。
看到他的回答后,我又追加了一个提问“如何避免更新操作同一条数据”?你也可以自行思考一下,再继续往下看。
后面的回答同样来自@LecKeyt同学
更新带来的数据不一致的情况,我个人认为要看具体业务,如果是实时性要求不高的可以用事件队列处理,如果要求强一致性那最好的方式应该是分布式事务保证了。
第九节课
Q现在市面上有诸多分布式实现方式你觉得哪一种性能更好
A建议考虑使用AT或Seata方式。
以上就是用户中心和电商系统这两个章节的思考题答案,希望能带给你一些启发。接下来,老师还会针对剩余的课后思考题,以及你的提问来作出解答。有任何问题,还是跟以前一样,欢迎你在留言区多多互动。