分布式系统案例课
杨波
前携程 / 拍拍贷技术总监,微服务技术专家
11809 人已学习
新⼈⾸单¥59
课程目录
已完结/共 66 讲
第一章 课程介绍 (2讲)
时长 09:20
时长 04:42
第二章 如何设计一个分布式计数服务 - 系统设计面试案例 (7讲)
第五章 如何设计一个高并发无状态的会话缓存服务 - 携程SessionServer案例 (5讲)
第十章 课程回顾&结课测试 (1讲)
分布式系统案例课
登录|注册
留言
17
收藏
沉浸
阅读
分享
手机端
回顶部
当前播放: 05 | 计数服务设计(上)
00:00 / 00:00
高清
  • 高清
1.0x
  • 2.0x
  • 1.5x
  • 1.25x
  • 1.0x
  • 0.75x
  • 0.5x
网页全屏
全屏
00:00
付费课程,可试看
01 | 课程介绍
02 | 内容综述
03 | 需求收集和总体架构设计
04 | 存储设计
05 | 计数服务设计(上)
06 | 计数服务设计(下)
07 | 查询服务设计
08 | 技术栈选型
09 | 进一步考量和总结
10 | PMQ 2.0项目背景
11 | PMQ 2.0的设计解析(上)
12 | PMQ 2.0的设计解析(中)
13 | PMQ 2.0的设计解析(下)
14 | PMQ 3.0的演进
15 | Kafka的动态重平衡是如何工作的?(上)
16 | Kafka的动态重平衡是如何工作的?(下)
17 | 消息队列设计和治理最佳实践
18 | 第四章目录和大纲
19 | 微服务的四大技术难题是什么?
20 | 如何解决微服务的数据一致性分发问题?
21 | 如何解决微服务的数据聚合Join问题?
22 | 如何解决微服务的分布式事务问题?(上)
23 | 如何解决微服务的分布式事务问题?(下)
24 | 阿里分布式事务中间件Seata解析
25 | Uber微服务编排引擎Cadence解析
26 | 如何理解Uber Cadence的架构设计?
27 | 如何实现遗留系统的解耦拆分?
28 | 拍拍贷系统拆分项目案例
29 | CQRS/CDC技术在Netflix的实践
30 | 第四章总结
31 | SessionServer项目背景
32 | 总体架构设计
33 | 如何设计一个高性能基于内存的LRU Cache?
34 | 如何设计一个高性能大容量持久化的ConcurrentHashmap?
35 | 设计评估和总结
36 | SaaS项目healthchecks.io的背景和架构(上)
37 | SaaS项目healthchecks.io的背景和架构(下)
38 | 如何设计一个轻量级的基于DB的延迟任务队列?
39 | 如何设计一把轻量级的锁?
40 | 如何设计一个分布式限流系统?
41 | 如何设计一个分布式TopK系统实现实时防爬虫?
42 | 第七章目标和大纲
43 | 为什么说ServiceMesh是微服务的未来(上)
44 | 为什么说ServiceMesh是微服务的未来(下)
45 | 解析Envoy Proxy(上)
46 | 解析Envoy Proxy(下)
47 | Envoy在Lyft的实践
48 | 解析Istio
49 | K8s Ingress、Istio Gateway和API Gateway该如何选择?(上)
50 | K8s Ingress、Istio Gateway和API Gateway该如何选择?(下)
51 | Spring Cloud、K8s和Istio该如何集成?
52 | 第八章目标和大纲
53 | 拍拍贷案例:大型网站架构是如何演进的?
54 | 最小可用架构:Minimum Viable Architecture(上)
55 | 最小可用架构:Minimum Viable Architecture(下)
56 | 如何构建基于OAuth2/JWT的微服务架构?(上)
57 | 如何构建基于OAuth2/JWT的微服务架构?(下)
58 | 拍拍贷案例:如何实现数据中心机房的迁移?
59 | 携程/Netflix案例:如何实现同城双活和异地多活?
60 | 第九章大纲
61 | 学习开源项目的6个层次和8种方法(上)
62 | 学习开源项目的6个层次和8种方法(中)
63 | 学习开源项目的6个层次和8种方法(下)
64 | 百万年薪架构师是如何炼成的?
65 | 解读一份大厂的研发岗职级体系
66 | 结课测试&结束语
登录 后留言

全部留言(17)

  • 最新
  • 精选
zhou
老师,用户在观看视频时放入消息队列,这个是否应该有专门一个服务去接收用户观看触发的计数请求,然后放入消息队列。也就是在技术服务前,还有一个接收技术请求的服务

作者回复: 对,课程演示的是一种方便教学的理想模型。实践中,一般通过Nginx或者网关的访问日志(access log),采集用户的视频点击观看日志,再发送到计数服务。这样就不耦合。

2020-06-26
5
0xABC
波波老师好,还有个问题再请教一下 还是 聚合-> 内部队列 -> db写入 这个pipeline,整个消费过程中,当 聚合-> 内部队列 成功后就提交 ack 给 MQ,但是这个提交的 ack 可能由于某种原因是否也会提交失败;这样就可能造成重试,所以说也有可能会出现重复消息,这样 聚合 出来的就会有重复的聚合结果,然后放入 内部队列 中,是否也要考虑 在 db 写入环境保证去重呢(是否也可以理解为 写入操作 最好也提供幂等的处理)??

作者回复: 对,对于至少一次交付(At Least Once)的消息队列,都需要考虑去重问题,如果涉及业务的话,还要考虑幂等,第三章也会讲到。一般在消息进入消息队列之前,可以给它加一个唯一的id,这样消费端既可以用缓存窗口(cache window)等技术做去重处理,也方便后续业务做幂等处理。

2020-06-19
2
4
约书亚
我也不太能理解internal queue的必要性。aggregator在db或网络问题时重试提交,感觉效果一样。internal queue如果本地持久化,也有丢数据的风险,如果依旧借用Kafka做冗余,那也面临写入时网络的抖动问题。

作者回复: 如果你的aggregator同时做聚合和写入DB的事情,不是不可以,但是会有一些问题,比方说: 1. 一个是你的aggreator同时干了两个事情,违反单一职责原则,后续如果要调整写入数据库逻辑,aggregator就得跟着一起改。后面发布也要一起发布,不能单独发布DB writer。如果有中间queue的话,DB writer暂时下线都没关系,queue会缓冲计算结果。 2. aggregator因为同时干两件事情,当写入数据库慢,可能阻Aggregator线程,甚至影响到聚合运算性能。 内部queue是持久化的,在企业开发中,一般认为数据能够落地(落磁盘文件,或者DB),那么数据就不会再丢,宕机了重启都能找回来。当然这个不是绝对,只是相对内存数据来说的,内存数据宕机就没有了。

2020-06-18
4
3
intomymind
在消费者端也就是Consumer MQ Client采用pull模式的话就已经减轻的后端数据的压力,Internal Queue 还有存在的必要吗,而且引入一个新的队列也增加了一个丢数据的风险点

作者回复: 有必要,尽管是pull模式,但是DB慢或者挂,或者之间的网络出现抖动/瞬断,这些问题在实际生产环境中都无法避免。

2020-06-16
6
3
Vincent_
老师好,结合上一篇缓存设计,好像redis这个nosql在nosql领域大多数情况都只当做一个不持久化数据也就是有过期时间的缓存,而不是当一个高可用的数据层。像上一章说的nosql可以用redis做吗?因为redis是内存级的操作,所以我们才不在需要持久化的情形里考虑使用他来代替其他磁盘级的db吗?

作者回复: redis的最常见使用场景是作为缓存(Cache)来用,比如把redis作为DB的缓存。nosql大致可以分为四种,KV缓存(包括redis)是一种,文档存储(如MongoDB)是一种,列式数据库(Hbase/Cassandra)是一种,还有图数据库(如Neo4j)也是一种。

2020-08-12
2
明月朔风
波波老师,Internal Queue,有什么好方法能保证不丢失吗?想过写本地文件,但是k8,一旦重启,不一定漂移到哪里去了

作者回复: k8s容器环境是麻烦一点,一种办法是考虑Persistent Volume持久卷,持久卷可以挂载磁盘或者远程存储。 另外一种办法,索性把计算结果再发送到kafka队列,再让DB Writer去kafka消费数据再写入DB。

2020-07-14
2
古德
波波老师好,有几个疑问交流一下 1.在这个架构设计中,Kafka消息是有可能重复发送,在接收端做幂等性判断时,具体怎么做比较好(该场景的业务数据感觉没法做) 2.如果DBWriter不可用,Internal Queue缓冲到磁盘或者本地数据库时,能不能对比较主流的实现方式介绍一下(具体用什么磁盘缓冲库,或者嵌入数据库等)

作者回复: 1. 消费端去重的一种简单做法,是每个消息进入队列时,header里头给一个唯一id,然后消费端利用缓存窗口技术进行去重,如果单位时间内某个id已经有缓存过,就去重丢弃。 2. 我之前就开源过做一个叫bigqueue(https://github.com/bulldog2011/bigqueue)的磁盘持久化queue,基于内存映射技术的,性能很高。你如果有研发能力,自己开发一个简化的磁盘queue,工作量其实也不是很大。嵌入式db可以考虑sqlite或者berkelyDB,都可以实现简单queue的功能。

2020-06-20
2
2
发条橙子 。
波波老师 小白问个问题 : 技术消费者的详细设计 , 从mq消费端开始到dbwriter是一个应用服务的在一个线程内处理好的么 ? 1. 按照时序图来说, 是在一个领域服务内(service层)完成聚合的逻辑然后写到自己本地的队列中(又是一个service)最后调用dbwriter service将结果更新到 db这个样子么 2. 如果消费端是集群服务 ,多个消费端同时做本地内存计算, 最后同步到db是采用增加的方式么

作者回复: 1. 一般queue的两头都需要一个线程,比方说这里的计数消费者里头有两个queue,所以第一个queue的前面有一个consumer thread,第一和第二个queue之间有一个aggregator聚合线程,第二个queue后面有一个DB writer线程。 2. 同步到DB就是一个批量插入(batch insert),其中每一条记录信息主要包括时间 + 视频id + 一分钟观看计数这些字段。

2020-07-27
1
飞翔
老师 DBwrite 一般失败几次 就把消息 扔到死信队列中呀。 还有DBwrite 写入database 失败之后 是立刻重试呢 还是需要过一段时间?

作者回复: 没有规定失败几次写入死信队列,一般可以设置成3次,最好做成动态可配置,可以按需动态调整。 立即重试可以,高级一点的可以按指数级退避再重试(退1秒重试,不行再退2秒,不行再退4秒。。。)

2020-06-21
1
飞翔
老师 deadletter queue 除了用kafka partition 外 还能用什么呀, 还有当数据写入到了deadletter queue 之后 这里边的数据怎么处理 啥时候 写入db呀

作者回复: 1. deadletter queue可以是本地的嵌入式DB,例如sqlite,或者berkeley DB,也可以是本地持久化queue,例如我开源的github.com/bulldog2011/bigqueue 2. 只要一个后台线程,定期监控deadletter queue,有消息的话定期重试写入DB即可。

2020-06-21
2
1
收起评论