字节跳动大规模企业级 HTTP 框架 Hertz 设计实践

字节跳动大规模企业级 HTTP 框架 Hertz 设计实践

日前,字节跳动技术社区ByteTech举办的第七期字节跳动技术沙龙圆满落幕,本期沙龙以《字节高性能开源微服务框架:CloudWeGo》为主题。在沙龙中,字节跳动字节跳动基础架构服务框架资深研发工程师高文举,跟大家分享了《大规模企业级HTTP框架的设计和实践》,本文根据分享整理而成。
本文将从以下五个方面介绍CloudWeGo大规模企业级HTTP框架Hertz:
在正式开始介绍第一部分的内容之前,先给大家展示一组关键词。2020年初Hertz立项,2020年10月,Hertz发布第一个可用版本。2022年6月,Hertz正式开源。截至目前,Hertz在字节内部已经支撑超过1.4万个业务服务,日峰值QPS超过5000万。
Hertz不仅支撑业务服务,同时还会横向支撑字节内部的各种基础组件,包括但不限于字节跳动服务网格控制面、公司级别压测平台以及FaaS,还包括各种业务网关等等。Hertz的高性能和极强的稳定性可以支撑业务复杂多变的场景。在公司内部Hertz接替了大量基于Gin框架开发的存量服务,大幅度降低了业务资源使用成本以及服务延时,助力公司层面的降本增效。
下面我们可以从Hertz出现的背景以及Hertz的设计目标和思路体会到,Hertz的出现绝不是偶然。
1.1基于Gin封装
众所周知,字节内部使用Golang比较早,在大约2014年左右,公司就已经开始尝试做一些Golang业务的转型。2016年,我们基于已开源的GolangHTTP框架Gin框架,封装了Ginex,这是Ginex刚开始出现的时期。
同时,2016年还是一个开荒的时代,这个时期框架伴随着业务快速野蛮地生长,我们的口号是“大力出奇迹”,把优先解决业务需求作为第一要务。Ginex的迭代方式是业务和框架侧在同一个仓库里面共同维护和迭代。
1.2问题显现
2017-2019年期间,也就是Ginex发布之后,问题逐渐显现。主要有以下几点:
Ginex是一个基于Gin的开源封装,所以它本身在迭代方面是受到一些限制的。一旦有针对公司级的需求开发,以及Bugfix等等,我们都需要和开源框架Gin做联合开发和维护,这个周期不能完全由我们自己控制。
由于我们和业务同学共同开发和维护Ginex框架,因此我们对于控制整个框架的走向没有完全的自主权,从而导致了整体代码混乱膨胀,到后期我们发现越来越难维护。
另外,我们能用Gin做的性能优化非常少,因为Gin的底层是基于Golang的一个原生库,所以如果我们要做优化,需要在原生库的基础上做很多改造,这个其实是非常困难的。
我们内部逐渐出现了一些新的场景,因此会有对HTTPClient的需求,支持Websocket、支持HTTP/2以及支持HTTP/3等等需求,而在原生的Ginex上还是很难扩展的这些功能需求。
1.3魔改开源框架
逐渐地,某些业务线开始做初步的尝试,他们会对另外的一些开源框架进行魔改。比较典型的例子是有一些业务线尝试基于Fasthttp进行魔改,Fasthttp是一款主打高性能的开源框架,基于它进行魔改可以短期内帮助业务解决问题。这种魔改现象带来的问题是,框架魔改是一些业务线自发的行为,各个业务线可能会基于自身业务特性进行各自维护,从而导致维护成本上升非常严重。
到这里我们仿佛陷入了Ginex的怪圈。如前段时间爆火的电视剧《开端》一样,我们仿佛是从一辆开往学院南路的45路公交车上醒来,发现自己要前往公司进行下一代Ginex框架的维护工作。
大家也可以思考一下,如果是你来应对这样的场景,你会怎么做呢?
1.4小结
第一章节的内容总结如下:
基于早期开源的GolangHTTP框架,实现了Ginex的封装。
框架混乱膨胀,框架的维护越来越困难,业务的新需求无法得到很好地满足。
我们需要思考如何跳出魔改的怪圈,把字节内部的企业级框架做得更好。
另外,还有一个遗留问题,就是应该如何跳出这个魔改的怪圈呢?这个问题第二章节会为大家进行解答。
2.1跳出怪圈
为了跳出魔改的怪圈,我们决定从以下三个方面开始着手。
既然Ginex是因为基于开源框架Gin,没法做一些灵活的控制,那我们就改为完全自主研发框架。自主研发框架的代码全链路自主可控,也可以避免引入任何三方不可控因素,这样我们能够对自己的框架有一个比较完备的掌控力。
下图列举了一些常规的质量控制手段。我要着重强调的是模糊测试,模糊测试在字节内部是广泛应用于Hertz框架的稳定性测试中。它的核心点在于通过一系列的模拟服务,尝试模拟出线上用户在使用我们的框架时,实际遇到的一些场景和使用方式。然后通过一些随机的算法,生成尽可能复杂、覆盖各种Case的场景,这可以让我们检测出一些潜在的问题。这套测试也在Hertz早期的质量建设中,帮助我们将一些问题防患于未然。
既然Ginex的问题是大家都在向里面写入内容,那么我们可以控制入口,建立一套完备的需求开发以及Review的闭环,控制迭代的整体流程,从而控制代码准入。同时我们配备统一的需求管理以及严格的发版准入规范,做一个标准的公司级别的框架。
举一个比较形象的例子,如果我们把下一代框架比作一个人——“框架人”,自主研发表示这个“框架人”首先会拥有对自己身体的主导权,他不会受到来自于环境或者他人的影响;质量控制表示“框架人”能够定期体检,提早发现一些潜在的疾病,将其扼杀于摇篮;严格准入表示“框架人”有科学的饮食摄入和自律的生活习惯。可想而知,如果我们能够做到以上三点,我们的“框架人”就能够拥有一个健康的体魄。
2.2痛点梳理
明确了应该如何跳出怪圈之后,我们还应该明确知道这个框架要具备哪些功能和特性,也就是首先应该聚焦到框架的核心痛点上。“框架人”不能只有健康的体魄,还应该拥有有趣的思想和灵魂。一个成熟的框架不仅仅要应对来自业务侧的需求,如功能需求、性能需求和易用稳定等,还要考虑框架自身的发展,而这一点恰恰是我们在Ginex的迭代过程中忽略的。
如下图右侧金字塔所示,最上层是高效支撑,毋庸置疑框架的存在肯定是为了支撑我们的业务需求。中间层是一个质量保证的红线框架,框架需要保证它自身的质量,只有以高质量完成的框架才能有自信承担字节内部的5000万QPS,以及各种各样的使用场景。金字塔的最底层是长期、可持续性发展,这也是作为未来想要保持持续迭代的框架最重要的一点。
2.3框架科学发展观
基于上一部分,我们可以进一步梳理出框架的需求痛点。痛点主要有两个方面:
在此基础上进一步抽象出框架的科学发展观:
后续我会针对这个科学发展观进一步阐述Hertz究竟是如何实现的。
2.4小结
第二章节的内容总结如下:
引入“框架人”的概念,帮助大家理解框架的自研、质量控制和严格准入。
为“框架人”注入有趣的灵魂,框架需要应对来自业务侧的多样化需求,还要保证自己的可持续性发展。
需求聚类,跳出局部。
Hertz框架是如何实现第二章节中提到的框架痛点和科学发展观的呢?本章节将具体进行介绍。
3.1分层抽象
首先介绍Hertz框架的架构设计。下图是一个请求从建立、连接到完成的全过程。左侧是客户端,右侧是服务端,在我们发起链接建立请求之后,链接建立完成;之后客户端发起请求到服务端,服务端进行路由处理,然后将路由导向业务逻辑处理;业务逻辑处理完毕后,服务端返回这个请求,完成一次HTTP请求的调用。
那么在这个过程中我们的框架到底做了哪些事情呢?从图中不难发现,首先框架进行了链接处理,其次是协议处理,之后基于路由做了逻辑分发,即路由处理,最后做了业务逻辑处理。我们把框架做成一个结构之后会发现,这个结构包含的就是这四部分。
基于这个逻辑,我们可以看一下Hertz的整体架构图。如下图所示,从下往上看红线框圈住的部分,可以发现这就是上文提到的请求建立的全过程。各层的能力及作用如下:
我们可以看到图中除了中间部分包含的四层,左右两侧各有两列。右侧是通用层Common,主要负责提供通用能力、常用的日志接口、链路追踪以及一些配置处理相关的能力等。左侧是Hertz的代码生成工具Hz,又称脚手架工具,它可以帮助我们在内部基于IDL快速地生成项目骨架,以加速业务迭代。
Hertz的分层设计是能够和代码组织结构一一映射的。下图是Hertz仓库里面的代码组织结构,可以看到根目录下的cmd包里面存放着Hz工具,在pkg包下存放着上述主要四层以及通用层Common。因此同学们看到架构设计图之后,可以直接在Github学习Hertz的代码。
Hertz:https://github.com/cloudwego/hertz
总体来说,Hertz的架构设计理念就是“简洁有序,保证让所有开发者轻松理解,在开发的过程中持续贯彻”。
3.2易用可扩展
那么基于Hertz的架构设计,应该如何展开易用性和可扩展性呢?下图是Hertz架构主要四个层级的抽象。
应用层提供了一些通用能力,包括绑定请求、响应渲染、服务发现/注册/负载均衡以及服务治理等等。其中,洋葱模型中间件的核心目的是让业务开发同学基于这个中间件快速地给业务逻辑进行扩展,扩展方式是可以在业务逻辑处理前和处理后分别插桩埋点做相应处理。一些比较有代表性的应用,包括日志打点、前置的安全检测,都是通过洋葱模型中间件进行处理的。
路由层也是非常通用的,主要提供静态路由、参数路由、为路由配置优先级以及路由修复的能力,如果我们的路由层没办法满足用户需求,它还能支撑用户做自定义路由的扩展。但实际应用中这些路由能力完全能够满足绝大多数用户的需求。
Hertz同时提供HTTP/1.1和HTTP/2,HTTP/3也是我们在建设中的能力,我们还会提供Websocket等HTTP相关的多协议支持,以及支持完全由业务决定的自定义协议层扩展。
目前我们已经内置了两个高性能的传输层实现。一个是基于CloudWeGo开源的高性能网络库Netpoll的传输层扩展,另一个是支持基于标准库的传输层扩展。此外,我们也同样能支持在传输层上进行自定义传输层协议扩展。
下图每一层中标红的能力都能够体现出,我们能够在框架的任何一个分层上支撑用户做最大程度的自由定制,这样可以最大程度地满足企业级内部用户和潜在用户的业务需求。如果同学们想要深入了解Hertz,可以参考CloudWeGo官网的Hertz部分,上述所有内容均有具体描述。
官网:https://www.cloudwego.io/zh/docs/hertz/
3.3性能探索
在性能方面,Hertz又是如何在自主可控的范围内做高性能探索的呢?
3.3.1场景描述
熟悉Hertz代码的同学会发现,我们的HTTP/1.1协议借鉴了一些Fasthttp的优化思路和手段。HTTP/1.1协议中的Header为不定长数据段,往往需要解析到最后一行,才能够确定是否完成解析。同时,为了减少系统调用次数,提升整体解析效率,涉及IO操作时,我们通常引入带buffer的IO数据结构。如下图所示,它的核心点是最下层的buffer,buffer是一个类似于一块完整的内存空间,我们可以将IO读到的数据放进这个空间做暂存。
3.3.2bufio.Reader的问题
这样做出现的问题是,原生的bufio.Reader长度是固定的,请求的Header大小超出buffer长度后,.Peek()方法直接报错(ErrBufferFul),无法完成既定语义功能。
3.3.3一些可能的解
对于上述问题,其实有一些可能的解决方法:
3.3.4真实使用环境复杂多变
字节内部的使用场景非常多,我们不仅要支持各种业务线的开发,还要支持一些横向的基础组件。不同的业务,不同的场景,数据规模各异。如何成为通用且高效地解决bufio.Reader的问题成为Hertz面临的内部重要挑战。我们既然已经站在Fasthttp这个“巨人”的肩膀上了,能否往前再走一步呢?
答案是肯定的。基于内部的使用场景,同时结合Netpoll的优势,我们设计出了自适应linkedbuffer,并且用它替代掉了原生的bufio.Reader。从下图可以看到,我们的buffer不再是一个固定长度的buffer,而是一条链,这条链上的每一个buffer大小能够根据线上真实请求进行动态扩缩容调整,同时搭配Netpoll中基于LT触发的模型做数据预拷贝。从实施效果上来看,这个自适应调整能够让我们的业务方完全无感地支撑任何他们的业务特性。也是因为我们能够将buffer进行动态扩缩容调整,从而能够保证在协议层最大程度做到零拷贝协议解析,这能够带来整体解析上的性能提升,时延也会更低。
3.3.5针对HTTP/1.1进行中的优化
因为目前在字节内部HTTP/1.1还是一个比较主流的协议,所以我们基于HTTP/1.1做了很多尝试。
首先是协议层探索。我们正在尝试基于HeaderPasser的重构,把解析Header的流程做得更高效。我们还尝试了做一些传输层预解析,将一些比较固化的逻辑下沉到传输层做加速。
其次是传输层探索。这包括使用writev整合发送Header&Body达到减少系统调用次数的目的,以及通过新增接口整合.Peek()+.Skip()语义,在内部提供一个更高效的实现。
下图是Benchmark的开源数据。左侧第一张图是在同等的机器环境上,Hertz和横向的框架Gin、Fasthttp极限QPS比较情况,蓝线是Hertz处于较高极限QPS的状态。第二张图是TP99时延状态,第三张图是TP999时延状态,可以看到Hertz的整体时延是处于一个更低的水平上。
3.3.7字节跳动服务网格控制面从Gin迁移至Hertz
CloudWeGo公众号曾发布关于字节跳动服务网格控制面的文章,讲述字节跳动服务网格从Gin框架迁移到Hertz的落地实践。下图是他们代码展示的真实收益,从Gin框架替换成为Hertz框架后,CPU流量从大概快到4K降到大约只有2.5K,Goroutine数量从6w降到不足100个,Goroutine稳定性得到极大地提升。同时替换成Hertz后,框架相关的开销已经基本消失,服务网格在线上稳定承载了超过13MQPS的流量。
字节跳动服务网格基于Hertz框架的实践:https://mp.weixin.qq.com/s/koi9q_57Vk59YYtO9cyAFA
3.4小结
第三章节的内容总结如下:
解构HTTP框架,分层解耦。
提供了更丰富API和足够灵活的拓展能力,在每一层抽象中都提供了一个足够灵活的扩展能力应对可能的需求。
自适应buffer,零拷贝解析,未来将会进行更多的高性能探索。
我认为Hertz未来的发展规划主要围绕以下几个方面:首先,打造泛HTTP框架。我们的最终目标是希望Hertz能够解决在HTTP领域内的所有问题;其次,助力CloudWeGo,希望Hertz能够助力CloudWeGo打造一个企业级云原生微服务矩阵;最后希望Hertz能够持续服务更多的用户。
本次分享的主要内容总结如下:
最后欢迎对Hertz感兴趣的同学积极参与到CloudWeGo社区中,我们一起完善Hertz,共同建设CloudWeGo!
CloudWeGo是一套由字节跳动开源的、可快速构建企业级云原生微服务架构的中间件集合。它包含许多组件:GolangRPC框架Kitex,HTTP框架Hertz,RustRPC框架Volo,网络库Netpoll,Go语言Thrift编译器Thriftgo等等。通过结合社区优秀的开源产品和生态,可以快速搭建一套完善的云原生微服务体系。项目共同的特点是高性能、高扩展性、高可靠,专注于微服务通信与治理。CloudWeGo项目自2021年9月开源,至今开源1年,获得1w+star,代码贡献者人数已有140+,年度AwesomeContributor提名84位。更多生态能力对接,请参考kitex-contribhttps://github.com/kitex-contrib和hertz-contribhttps://github.com/hertz-contrib。
以上内容整理自第七期字节跳动技术沙龙《字节高性能开源微服务框架:CloudWeGo》,获取讲师PPT和回放视频,请在公众号“字节跳动技术团队”后台回复关键词“0827”。

主题测试文章,只做测试使用。发布者:最新稳定辅助网,转转请注明出处:https://www.744broad.com/17557.html

(0)
上一篇 2023年3月11日 上午1:51
下一篇 2023年3月11日 上午1:56

相关推荐

  • ​碟荐丨民歌时代的经典史诗,齐豫出道之作《橄榄树》

    ​碟荐丨民歌时代的经典史诗,齐豫出道之作《橄榄树》 民歌时代,这个离我们有些年头的节点,至今却还为老乐迷们津津乐道。从杨弦、胡德夫、李双泽,到再次革新音乐潮流的罗大佑、潘越云,短短十几年中,中国台湾的华语音乐从西洋音乐的追随者,蜕变成了百家争鸣的创作热土。而其中有两位重要人物,也深深影响了这个时代——民歌界的泰斗李泰祥,与至今仍活跃在一线的歌手齐豫。1979…

    RUST资讯 2023年2月13日
    60
  • 用实例学习 Rust——不是每个 println 都如此强大

    用实例学习 Rust——不是每个 println 都如此强大 今天我们来学习下Rust中的命令行打印。代码如下:注释的标号和下面的解释对应。如有任何问题,请添加微信公众号“读一读我”。 打赏赞微海报分享

    RUST资讯 2023年3月10日
    20
  • 快速固化、更耐腐蚀!防腐阻燃的粉末涂料在这里

    快速固化、更耐腐蚀!防腐阻燃的粉末涂料在这里 随着社会的发展高层建筑越来越多,高密度、结构复杂的建筑物也开始遍布大江南北。一旦发生火灾,灭火救援的难度很大,极易造成较大的经济损失和人员伤亡。“916”长沙电信大厦火灾就是一个典型案例,火灾现场浓烟滚滚,数十层楼体燃烧剧烈,让人触目惊心。不得不承认,此次火灾事故中,现场的防火门阻止了火势蔓延和烟气扩散,为人员疏…

  • 《绝地求生》最初的回忆:网友盼望经典大厅音乐归来

    《绝地求生》最初的回忆:网友盼望经典大厅音乐归来 近日,Reddit有网友发帖称希望蓝洞将原版大厅BGM换回来,并附上了一段20分钟长名为“PUBG-LobbyMusic#1”音乐。(帖子与视频)而下方的评论大部分网友都是希望老版BGM回来的:-尽管这个BGM是在7个月前更新换掉的,但我感觉这个BGM真的对我来说很久远了。我并不知道为什么这个BGM让我这么的…

    RUST资讯 2023年2月13日
    70
  • 清末民初的四川汶川县飞沙关

    清末民初的四川汶川县飞沙关 1908年5月29日,四川汶川县飞沙关。英国人亨利威尔逊拍摄。据《汶川县志》载:县治二十余公里处有飞沙关,山上有一平地,地名石纽山刳儿坪。《禹志》云:禹生于石纽。《益州记》述:石纽山者,今其地名刳儿坪,坪上原有禹王庙,圣母祠,社稷,今已毁,尚有遗志。飞沙关口绝壁上刻有“石纽山”三个大字。字迹苍劲古朴,传为唐时李白手书题记,勘称书法…

  • DOTA2新手攻略:游戏里有哪些让人恶心的被动技能

    DOTA2新手攻略:游戏里有哪些让人恶心的被动技能 俗话说前人栽树,后人乘凉,眼看着这个问题放在这,却鲜有正经回答的也不是个事儿,今天笔者就带大家来盘点一下DOTA中,那些让人几近抓狂的恶心被动技能吧!当前版本(7.20E)中恶心的被动技能伐木机-活性护甲★★★☆作为一个增加存活率的被动技能,活性护甲本身并不具备杀伤力,然而伐木机之所以能被称之为线霸,正是凭…

    RUST资讯 2023年2月17日
    50
  • Dunn-Edwards 2021色彩+设计 流行趋势 04

    Dunn-Edwards 2021色彩+设计 流行趋势 04 Lagom:aSwedishtermthatsignifiestherightamountorbalancedperfection.Nottoolittle,nottoomuch—justright.Lagomiseasygoing,unplugging,connectingwithothersi…

    RUST资讯 2023年2月17日
    100
  • Rust 会成为 JavaScript 基础设施的未来吗?

    Rust 会成为 JavaScript 基础设施的未来吗? 作者:佚名来源:Rust编程指北Rust最初由Mozilla创建,是一种快速、可靠、内存效率高且非常流行的编程语言,专为提高性能和安全性而设计。它连续6年被StackOverflow调查评为最喜爱的编程语言,并在超大规模的公司使用,如Facebook,苹果,亚马逊,微软和谷歌等用于系统基础设施、加密…

    RUST资讯 2023年2月20日
    80
  • 谁说程序员没有“表达能力”?

    谁说程序员没有“表达能力”? 程序员、码农、理工男,对于外界来说一般都是木讷,呆板的一个形象,然而对于程序员来说真的就是如同外界人们所认为的不善于表达,水壶煮饺子,灵感说不出嘛?其实不是啦,对于我们这个群体来说,有着非常多的使用工具,与外界的认为完全相反,只要熟练使用一些工具,我们可以非常完美地诠释——表达,这个词语。本文旨在从代码分享,思路阐述和演示文稿等…

  • 为 Linux 内核添加 Rust 支持的补丁已准备就绪

    为 Linux 内核添加 Rust 支持的补丁已准备就绪 出品|开源中国文|Travis7月4日,一套修订后的补丁被提交至Linux内核的邮件列表中,该补丁为在Linux内核中以Rust作为辅助编程语言提供了支持,借助Rust可以提高Linux内核和内存的安全。整套补丁包含17个子项,不光为Linux内核提供了初步的Rust支持,还提供了一个驱动实例,总共有…

关注微信