手把手带你写一个 Web 框架
叶剑峰
腾讯高级工程师,前滴滴技术专家
22731 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 42 讲
特别放送 (1讲)
手把手带你写一个 Web 框架
15
15
1.0x
00:00/00:00
登录|注册

02|Context:请求控制器,让每个请求都在掌控之中

ConnContext
BaseContext
生成最终的 Context 的流程
是否超时标记位
写保护机制
第三步监听
第二步创建一个新的 Goroutine 来处理业务逻辑
第一步生成一个超时的 Context
自定义 Context
自定义 Context
自定义 Context
控制器
控制器
Context 是怎么产生的
Context 是怎么产生的
在整个树形逻辑链条中,用上下文控制器 Context,实现每个节点的信息传递和共享
思考题
小结
超时事件触发结束之后
异常事件、超时事件触发时
为单个请求设置超时
封装一个自己的 Context
控制器
Context 标准库的设计思路
context 标准库的解决思路
为了防止雪崩
思考题
小结
边界场景
为单个请求设置超时
封装一个自己的 Context
context 标准库设计思路
标准库设计思路
Context: 请求控制器,让每个请求都在掌控之中

该思维导图由 AI 生成,仅供参考

你好,我是轩脉刃。
上一讲我们使用 net/http 搭建了一个最简单的 HTTP 服务,为了帮你理解服务启动逻辑,我用思维导图梳理了主流程,如果你还有不熟悉,可以再回顾一下。
今天我将带你进一步丰富我们的框架,添加上下文 Context 为请求设置超时时间。
从主流程中我们知道(第三层关键结论),HTTP 服务会为每个请求创建一个 Goroutine 进行服务处理。在服务处理的过程中,有可能就在本地执行业务逻辑,也有可能再去下游服务获取数据。如下图,本地处理逻辑 A,下游服务 a/b/c/d, 会形成一个标准的树形逻辑链条。
在这个逻辑链条中,每个本地处理逻辑,或者下游服务请求节点,都有可能存在超时问题。而对于 HTTP 服务而言,超时往往是造成服务不可用、甚至系统瘫痪的罪魁祸首
系统瘫痪也就是我们俗称的雪崩,某个服务的不可用引发了其他服务的不可用。比如上图中,如果服务 d 超时,导致请求处理缓慢甚至不可用,加剧了 Goroutine 堆积,同时也造成了服务 a/b/c 的请求堆积,Goroutine 堆积,瞬时请求数加大,导致 a/b/c 的服务都不可用,整个系统瘫痪,怎么办?
最有效的方法就是从源头上控制一个请求的“最大处理时长”,所以,对于一个 Web 框架而言,“超时控制”能力是必备的。今天我们就用 Context 为框架增加这个能力。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

本文介绍了如何使用Context控制器来管理每个请求的超时时间。作者首先解释了在HTTP服务中,每个请求都会创建一个Goroutine进行服务处理,而超时问题往往是导致服务不可用和系统瘫痪的主要原因。为了防止雪崩效应,作者介绍了使用context标准库来控制超时的设计思路和功能。通过示例和代码解释,作者详细介绍了context标准库的设计思路和功能,包括WithCancel、WithTimeout和WithDeadline等函数的使用方法和原理。文章通过生动的比喻和图示,帮助读者理解了Context的树形结构和上下游节点的管理关系。总的来说,本文深入浅出地介绍了如何使用Context控制器来管理请求的超时时间,为读者提供了清晰的技术指导。文章还介绍了如何封装自定义的Context,提供了更强大的功能,包括获取请求、返回结果和实现标准库的Context接口。通过对request和response的封装,作者展示了如何简化控制器的代码,提高框架的易用性。整体而言,本文内容丰富,技术性强,对于需要深入了解Context控制器和自定义Context的读者具有很高的参考价值。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《手把手带你写一个 Web 框架》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(41)

  • 最新
  • 精选
  • qinsi
    置顶
    “context作为函数的第一个参数”大概有两层意思。一是作为函数的参数传入。这个应该是针对在一个struct的多个方法中共享一个context的情况说的。因为每个方法都有可能需要创建子context,所以不应该共享而是应该显式传递。二是作为第一个参数。这个多半是一种约定。在支持可变长参数的语言中,固定参数只能出现在可变参数的前面。而作为与业务逻辑关系不大的context,出现在第一个的位置也方便也其他参数作区分。 说到与业务逻辑关系不大,个人以为显式传递context是对业务逻辑的侵入,更别提单元测试的时候还需要适当地mock掉。目前代码里请求控制和请求实现混在一起的情况后面应该会改掉吧?

    作者回复: context作为第一个参数在实际工作中是非常有用的一个实践。不管我们是设计一个函数,或者设计一个结构体的方法,或者服务的时候,我们一旦养成了将第一个参数作为context的习惯,那么这个context在相互调用的时候,就会传递下去。这里会带来几个好处: 1 链路通用内容传递。context中是可以通过WithValue方法将某些字段封装在context里面,并且传递的。最常见的字段是traceId, spanId。而在日志中带上这些ID,再将日志收集起来,我们就能进行分析了。这也是我们现在比较流行的全链路分析的原理。 2 链路统一设置超时。我们在定义一个服务的时候,将第一个参数固定设置为context,则可以通过这个context进行超时设置,而这个超时设置,是由上游调用方进行设置,这样就形成了一个统一的超时设置机制。比如A设置了5s超时,自己使用了1s,传递到下游B服务的时候,设置B的context超时时长为4s。这样全链路超时传递下去,就能保持统一设置了。 是的,请求控制和请求实现混在一起的情况,后面引入middleware会改掉的。

    2021-09-15
    23
  • zhao
    代码里面context的封装跟gin的源代码真是像极了,对照来看,对框架的理解又加深了一些。

    作者回复: 你好,是的context的封装和gin的代码很像,本质就是通过自己开发对开源的gin会有进一步理解。

    2021-09-17
    2
    7
  • 心平气和
    真的很好,我读了四遍,才读懂老师代码的强大。

    作者回复: 感谢

    2022-06-29归属地:北京
    2
  • 我在睡觉
    你好老师,这个代码运行之后,一次HTTP请求过来,ServeHTTP函数会被调用两次,请问是为什么?

    作者回复: 有例子么?一个请求应该只会运行一次的,有更多信息没

    2021-11-26
    4
    1
  • 2345
    文章写得很好,赞一个,比较有深度

    作者回复: 感谢支持,欢迎继续参与。

    2021-09-22
    1
  • 0mfg
    叶老师您好,把分支2 git下来尝试运行,报错如下,求指教,谢谢 # command-line-arguments .\main.go:10:2: undefined: registerRouter

    作者回复: https://github.com/gohade/coredemo/blob/geekbang/02/route.go 确认下你的目录下有route.go文件么

    2021-09-22
    12
    1
  • happy learn
    到底是一个请求一个goroutine还是一个连接一个goroutine,前后两篇文章说的不一致

    作者回复: 01梳理思维导图的时候说,接受一个新的请求连接时,会创建一个新结构,开启一个goroutine来服务。所以这两种说法其实是一致的

    2021-09-21
    1
  • 恶魔果实
    为什么会导致服务b和服务c的瞬时请求加大?这里不是很理解。 a请求失败,但是b,c请求是成功的呀。

    作者回复: 这个例子举的确实不好。我的本意是如果a请求失败,整个上游可能有重试机制,导致其他的请求连接增加。 我这里可能换一个方式举例更好,下游超时导致上游连接数增加。已经联系编辑进行更新了。 谢谢提醒。

    2021-09-18
    1
  • 怎么睡才能做这种梦
    看完这一章,感觉目前还没达到这个水平,难以跟进呀

    作者回复: 加油,原理确实很难讲到不生涩,但是需要细看

    2023-02-14归属地:湖北
  • helloworld
    在发出取消信号的时候,是不是所有子goroutine中都得有监听ctx.Done()并主动结束goroutine的代码逻辑,才能让所有gourutine都结束,还是说,不需要这样的逻辑所有就可以实现呢

    作者回复: 是需要有的,如果你的子goroutine没有监听ctx.Done主动结束自己的逻辑,是无法主动停止的

    2021-11-24
    2
收起评论
显示
设置
留言
41
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部