范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

字节跳动开源GoHTTP框架Hertz设计实践

  前言
  Hertz 是字节跳动服务框架团队研发的超大规模的企业级微服务 HTTP 框架,具有高易用性、易扩展、低时延等特点。在经过了字节跳动内部一年多的使用和迭代,如今已在 CloudWeGo 正式开源。目前,Hertz 已经成为了字节跳动内部最大的 HTTP 框架,线上接入的服务数量超过 1 万,峰值 QPS 超过 4 千万。除了各个业务线的同学使用外,也服务于内部很多基础组件,如:函数计算平台 FaaS、压测平台、各类网关、Service Mesh 控制面等,均收到不错的使用反馈。在如此大规模的场景下,Hertz 拥有极强的稳定性和性能,在内部实践中某些典型服务,如框架占比较高的服务、网关等服务,迁移 Hertz 后相比 Gin 框架,资源使用显著减少,CPU 使用率随流量大小降低 30%-60%,时延也有明显降低。
  Hertz 坚持 内外维护一套代码, 为开源使用提供了强有力的保障。通过开源, Hertz 也将丰富云原生的 Golang 中间件体系,完善 CloudWeGo 生态矩阵,为更多开发者和企业搭建云原生化的大规模分布式系统,提供一种现代的、资源高效的的技术方案。
  本文将重点关注 Hertz 的架构设计与功能特性。  项目缘起
  最初,字节跳动内部的 HTTP 框架是对 Gin 框架的封装,具备不错的易用性、生态完善等优点。随着内部业务的不断发展,高性能、多场景的需求日渐强烈。而 Gin 是对 Golang 原生 net/http 进行的二次开发,在按需扩展和性能优化上受到很大局限。因此,为了满足业务需求,更好的服务各大业务线,2020 年初,字节跳动服务框架团队经过内部使用场景和外部主流开源 HTTP 框架 Fasthttp、Gin、Echo 的调研后,开始基于自研网络库 Netpoll 开发内部框架 Hertz,让 Hertz 在面对企业级需求时,有更好的性能及稳定性表现,也能够满足业务发展和应对不断演进的技术需求。  架构设计
  Hertz 设计之初调研了大量业界优秀的 HTTP 框架,同时参考了近年来内部实践中积累的经验。为了保证框架整体上满足:1. 极致性能优化的可能性;2. 面对未来不可控需求的扩展能力, Hertz 采用了 4 层分层设计,保证各个层级功能内聚,同时通过层级之间的接口达到灵活扩展的目标。整体架构图如图 1 所示。
  图 1:Hertz 架构图
  Hertz 从上到下分为:应用层、路由层、协议层和传输层,每一层各司其职,同时公共能力被统一抽象到公共层(common),做到跨层级复用。另外,同主库一同发布的还有作为子模块的 Hz 脚手架,它能够协助使用者快速搭建出项目核心骨架以及提供实用的构建工具链。  应用层
  应用层是和用户直接交互的一层,提供丰富易用的 API,主要包括 Server、Client 和一些其他通用抽象。Server 提供了注册 HandlerFunc、Binding、Rendering 等能力;Client 提供了调用下游和服务发现等能力;以及抽象一个 HTTP 请求所必须涉及到的请求(Request)、响应(Response)、上下文(RequestContext)、中间件(Middleware)等等。Hertz 的 Server 和 Client 都能够提供中间件这样的扩展能力。
  应用层中一个非常重要的抽象就是对 Server HandlerFunc 的抽象。早期,Hertz 路由的处理函数 (HandlerFunc)中并没有接收标准的 context.Context,我们在大量的实践过程中发现,业务方通常需要一个标准的上下文在 RPC Client 或者日志、Tracing 等组件间传递,但由于请求上下文(RequestContext)生命周期局限于一次 HTTP 请求之内,而以上提到的场景往往存在异步的传递和处理,导致如果直接传递请求上下文,会导致出现一些数据不一致的问题。为此我们做了诸多尝试,但是因为核心原因在于请求上下文(RequestContext)的生命周期无法优雅的按需延长,最终在各种设计权衡下,我们在路由的处理函数签名中增加一个标准的上下文入参,通过分离出生命周期长短各异的两个上下文的方式,从根本上解决各种因为上下文生命周期不一致导致的异常问题,即:  type HandlerFunc func(c context.Context, ctx *app.RequestContext) 路由层
  路由层负责根据 URI 匹配对应的处理函数。
  起初,Hertz 的路由基于 httprouter 开发,但随着使用的用户越来越多,httprouter 渐渐不能够满足需求,主要体现在 httprouter 不能够同时注册静态路由和参数路由,即  /a/b ,/:c/d  这两个路由不能够同时注册;甚至有一些更特殊的需求,如/a/b 、/:c/b  ,当匹配 /a/b  路由时,两个路由都能够匹配上。
  Hertz 为满足这些需求重新构造了路由树,用户在注册路由时拥有很高的自由度:支持静态路由、参数路由的注册;支持按优先级匹配,如上述例子会优先匹配静态路由  /a/b  ;支持路由回溯,如注册 /a/b 、/:c/d ,当匹配 /a/d  时仍然能够匹配上;支持尾斜线重定向,如注册 /a/b ,当匹配 /a/b/  时能够重定向到 /a/b  上。Hertz 提供了丰富的路由能力来满足用户的需求,更多的功能可以参考 Hertz 配置文档。 协议层
  协议层负责不同协议的实现和扩展。
  Hertz 支持协议的扩展,用户只需要实现下面的接口便可以按照自己的需求在引擎(Engine) 上扩展协议,同时也支持通过 ALPN 协议协商的方式注册。Hertz 首批只开源了 HTTP1 实现,未来会陆续开源 HTTP2、QUIC 等实现。协议层扩展提供的灵活性甚至可以超越 HTTP 协议的范畴,用户完全可以按需注册任意符合自身需求的协议层实现,并且加入到 Hertz 的引擎中来,同时,也能够无缝享受到传输层带来的极致性能。  type ServerFactory interface {    New(core Core) (server protocol.Server, err error) }  type Server interface {    Serve(c context.Context, conn network.Conn) error } 传输层
  传输层负责底层的网络库的抽象和实现。
  Hertz 支持底层网络库的扩展。Hertz 原生完美适配 Netpoll,在时延方面有很多深度的优化,非常适合时延敏感的业务接入。Netpoll 对 TLS 能力的支持有待完善,而 TLS 能力又是 HTTP 框架必备能力,为此 Hertz 底层同时支持基于 Golang 标准网络库的实现适配,支持网络库的一键切换,用户可根据自己的需求选择合适的网络库进行替换。如果用户有更加高效的网络库或其他网络库需求,也完全可以根据需求自行扩展。  Hz 脚手架
  与 Hertz 一并开源的还有一个易用的命令行工具 Hz,用户只需提供一个 IDL,根据定义好的接口信息,Hz 便可以一键生成项目脚手架,让 Hertz 达到开箱即用的状态;Hz 也支持基于 IDL 的更新能力,能够基于 IDL 变动智能地更新项目代码。目前 Hz 支持了 Thrift 和 Protobuf 两种 IDL 定义。命令行工具内置丰富的选项,可以根据自己的需求使用。同时它底层依赖 Protobuf 官方的编译器和自研的 Thriftgo 的编译器,两者都支持自定义的生成代码插件。如果默认模板不能够满足需求,完全能够按需定义。
  未来,我们将继续迭代 Hz,持续集成各种常用的中间件,提供更高层面的模块化构建能力。给 Hertz 的用户提供按需调整的能力,通过灵活的自定义配置打造一套满足自身开发需求的脚手架。  Common 组件
  Common 组件主要存放一些公共的能力,比如错误处理、单元测试能力、可观测性相关能力(Log、Trace、Metrics 等)。对于服务可观测性的能力,Hertz 提供了默认的实现,用户可以按需装配;如果用户有特殊的需求,也可以通过 Hertz 提供的接口注入。比如对于 Trace 能力,Hertz 提供了默认的实现,也提供了将 Hertz 和 Kitex 串起来的 Example。如果想注入自己的实现,也可以实现下面的接口:  // Tracer is executed at the start and finish of an HTTP. type Tracer interface {         Start(ctx context.Context, c *app.RequestContext) context.Context         Finish(ctx context.Context, c *app.RequestContext) } 功能特性中间件
  Hertz 除了提供 Server 的中间件能力,还提供了 Client 中间件能力。用户可以使用中间件能力将通用逻辑(如:日志记录、性能统计、异常处理、鉴权逻辑等等)和业务逻辑区分开,让用户更加专注于业务代码。Server 和 Client 中间件使用方式相同,使用  Use  方法注册中间件,中间件执行顺序和注册顺序相同,同时支持预处理和后处理逻辑。
  Server 和 Client 的中间件实现方式并不相同。对于 Server 来说,我们希望减少栈的深度,同时也希望中间件能够默认的执行下一个,用户需要手动终止中间件的执行。因此,我们将 Server 的中间件分成了两种类型,即不在同一个函数调用栈(该中间件调用完后返回,由上一个中间件调用下一个中间件,如图 2 中 B 和 C)和在同一个函数调用栈的中间件(该中间件调用完后由该中间件继续调用下一个中间件,如图 2 中 C 和 Business Handler)。
  图 2: 中间件链路
  其核心是需要一个地方存下当前的调用位置 index,并始终保持其递增。恰好 RequestContext 就是一个存储 index 合适的位置。但是对于 Client,由于没有合适的地方存储 index,我们只能退而求其次,抛弃 index 的实现,将所有的中间件构造在同一调用链上,需要用户手动调用下一个中间件。  流式处理
  Hertz 提供 Server 和 Client 的流式处理能力。HTTP 的文件场景是十分常见的场景,除了 Server 侧的上传场景之外,Client 的下载场景也十分常见。为此,Hertz 支持了 Server 和 Client 的流式处理。在内部网关场景中,从 Gin 迁移到 Hertz 后,cpu 使用量随流量大小不同可节省 30%-60% 不等,服务压力越大,收益越大。Hertz 开启流式功能的方式也很容易,只需要在 Server 上或 Client 上添加一个配置即可,可参考 CloudWeGo 官网 Hertz 文档的流式处理部分。
  由于 Netpoll 采用 LT 的触发模式,由网络库主动将将数据从 TCP 缓冲区读到用户态,并存储到 buffer 中,否则 epoll 事件会持续触发。因此 Server 在超大请求的场景下,由于 Netpoll 持续将数据读到用户态内存中,可能会有 OOM 的风险。HTTP 文件上传场景就是一个典型的场景,但 HTTP 上传服务又是很常见的场景,因此我们支持标准网络库 go net,并针对 Hertz 做了特殊优化,暴露出  Read()  接口,防止 OOM 发生。
  对于 Client,情况并不相同。流式场景下会将连接封装成  Reader  暴露给用户,而 Client 有连接池管理,那这样连接就多了一种状态,何时关连接,何时复用连接成了一个问题。由于框架侧并不知道该连接何时会用完,框架侧复用该连接不现实,会导致串包问题。由于 GC 会关闭连接,因此我们起初设想流式场景下的连接交由用户后,由 GC 负责关闭,这样也不会导致资源泄漏。但是在测试后发现,由于 GC 存在一定时间间隔,另外 TCP 中主动关闭连接的一方需要等待 2RTT,在高并发场景下会导致 fd 被打满的情况。最终我们提供了复用连接的接口,对于性能有场要求用户,在使用完连接后可以将连接重新放入连接池中复用。 性能表现
  Hertz 使用字节跳动自研高性能网络库 Netpoll,在提高网络库效率方面有诸多实践,参考已发布文章字节跳动在 Go 网络库上的实践。除此之外,Netpoll 还针对 HTTP 场景进行优化,通过减少拷贝和系统调用次数提高吞吐以及降低时延。为了衡量 Hertz 性能指标,我们选取了社区中有代表性的框架 Gin(net/http)和 Fasthttp 作为对比,如图 3 所示。可以看到,Hertz 的极限吞吐、TP99 等指标均处于业界领先水平。未来,Hertz 还将继续和 Netpoll 深度配合,探索 HTTP 框架性能的极限。
  图 3:Hertz 和其他框架性能对比  一个 Demo
  下面简单演示一下 Hertz 是如何开发一个服务的。  首先,定义 IDL,这里使用 Thrift 作为 IDL 的定义(也支持使用 Protobuf 定义的 IDL),编写一个名为 Demo 的 service。这个服务有一个 API: Hello,它的请求参数是一个 query,响应是一个包含一个 RespBody 字段的 Json。  // idl/hello.thrift namespace go hello.example  struct HelloReq {     1: string Name (api.query="name"); }  struct HelloResp {     1: string RespBody; }  service HelloService {     HelloResp Hello(1: HelloReq request) (api.get="/hello"); } 接下来我们使用 hz 生成代码,并整理和拉取依赖  $ hz new -idl idl/hello.thrift -mod Demo $ go mod tidy && go mod verify 填充业务逻辑,比如我们返回  hello, ${Name} ,那我们在biz/handler/example/hello_service.go  中添加以下代码即可 // Hello . // @router /hello [GET] func Hello(ctx context.Context, c *app.RequestContext) {     var err error     var req example.HelloReq     err = c.BindAndValidate(&req)     if err != nil {         c.String(400, err.Error())         return     }      resp := new(example.HelloResp)     resp.RespBody = "hello, " + req.Name     c.JSON(200, resp) } 编译并运行项目  $ go build $ ./Demo
  到现在一个简单的 Hertz 项目已经生成,下面我们来测试一下  $ curl http://localhost:8888/hello?name=Xiaoming // 如果看到以下返回说明服务已经正常启动起来啦 $ {"RespBody":"hello, Xiaoming"}
  (以上 demo 可以在 hertz-examples 中查看) 之后就可以愉快的构建自己的项目了。  后记
  希望以上的分享能够让大家对 Hertz 有一个整体上的认识。同时,我们也在不断地迭代 Hertz、完善 CloudWeGo 整体生态。欢迎各位感兴趣的同学们加入我们,共同建设 CloudWeGo。  参考资料Hertz: https://github.com/cloudwego/hertz   Hertz Doc: https://www.cloudwego.io/zh/docs/hertz/   字节跳动在 Go 网络库上的实践: https://www.cloudwego.io/zh/blog/2021/10/09/%E5%AD%97%E8%8A%82%E8%B7%B3%E5%8A%A8%E5%9C%A8-go-%E7%BD%91%E7%BB%9C%E5%BA%93%E4%B8%8A%E7%9A%84%E5%AE%9E%E8%B7%B5/

换人真起作用了!全靠上中野,BLG新阵容赢下LGD,但形势不容乐观自上次将Doggo下放二队启用新人AD之后,BLG本场比赛赛前提交名单时再次整活,将教练位置换为了原助理教练Duan,取代了主教练叉烧的位置。今天这个新教练新AD的阵容迎来了自己的衰退忧虑主导市场美股走势不容乐观当地时间7月5日,美国股市涨跌互现,但对于经济衰退的忧虑仍旧主导市场。随着越来越多的金融机构发布衰退警告,投资者对于未来走势仍偏悲观。市场分析人士认为,从各项数据来看,美国经济活动摩苏尔人民过去的日子水深火热,未来也不容乐观,究竟是为何?全球之旅我在伊拉克摩苏尔大家好,我是申典启,一个实地走访世界各地,关注全球华人的旅行者。今天走在摩苏尔街道上,仿佛来到了灾难片现场,街头大量的高楼都留下了导弹的痕迹,一些楼房的墙体北青主裁张雷第2助理裁判张雪森因误判受到内部处罚直播吧6月28日讯在中超第6轮对成都蓉城的比赛中,因俱乐部官员对裁判有暴力行为,深圳队遭到了足协的重磅罚单。据北京青年报报道,主裁张雷第2助理裁判张雪森也因为误判而受到内部处罚。在中国队遭逆转,吞下开门黑!出线形势不容乐观,今晚过招奥运冠军6月22日下午,中国三人制男篮出击,面对荷兰队,首秀希望拿到开门红。比赛难度不小,但是中国队的小伙子上来就发力,竟然打出62的领先开局,这一切多么让人不可思议。可惜的是,接下来,荷炎夏终有时,静候凉意我是不惑,对人生大抵上比较自得其乐,惟今年的夏天困住了生活的激情,在热浪滚滚中缠绵着光阴,吃瓜与躺平,期待与耐心,成为这个夏天大部分的心情,想来这漫长的夏天终会有一个结局,且静心守观电子竞技发展有感作者肖羽君电子竞技是运动,而不是游戏,虽只是二字之差,却造就了一个新兴的产业。由此引起的羊群效应,最终能形成一个巨大的产业链。如今,在新老电竞的交替下,电竞已然不是一开始父母老师口俄罗斯首次展出拟自建空间站模型,外媒猜测俄罗斯国家航天集团15日首次展出拟自建空间站的模型,引发媒体推测,俄罗斯确实计划退出国际空间站项目。据路透社报道,这个模型当天在莫斯科附近举办的军队2022国际军事技术论坛展出。俄三星flip4fold4怎么样?三星新品使用介绍三星flip4fold4怎么样三星新品使用介绍时隔一年,三星又叒叕发布了折叠屏产品GalaxyZFlip4和GalaxyZFold4,作为折叠屏销冠的继承者,flip4和fold4硬件性能质变的今天,不要让显示器成为瓶颈小背景随着PC配置的不断提升,人们拥有高性能电脑的成本可以说是越来越低的,再加上游戏开发工具的更新带来游戏画质的大踏步提高,电影级画质体验已经越来越唾手可得。既然玩家用户群的配置越魅蓝官宣将于8月18日晚1900举行新品发布会IT之家8月16日消息,昨日对发布会进行预热以后,今天魅蓝官方正式宣布将于8月18日晚1900举行新品发布会,主题为秋日的新生。本次官宣依旧没有说明会发布什么新品,但从海报上可以看
断奶又断供?俄乌冲突加剧,比亚迪半导体不幸上市自然界的残酷,莫过于刚刚离开母巢的雏鸟,迎头就撞上了一场暴风雪。金融界亦是如此。在今年1月份,素有车芯第一股之称,在去年8月18日曾一度被中止审查的比亚迪半导体,终于如愿以偿地通过白酒生物医药半导体新能源车证券板块下周的走势解读3。12日白酒,生物医药,半导体,光伏,新能源车,证券板块下周怎么走?1白酒行业本周放量收假阳十字星。连续一阶段的震荡回调,这个位置收放量十字星,说明有资金入场,企稳反弹的概率较大美国横插一脚,意大利收钱后翻脸撕毁中企收购案,还想狠罚一笔意大利阻止中企收购军用无人机企业文闲田西方对中企的打压从未停止!日前,意大利公然撕毁了一份中国投资者与该国军用无人机企业的收购案。据环球网报道,有消息人士透露,本月10日,意政府宣谈一谈我对未来黄金走势的看法最近有很多投资者问我老师黄金是不是已经到顶了?这个走势是不是和2011年一样走的是双头顶。问的人太多了,我就在这里说一下我个人对黄金的看法。黄金价格走势图目前黄金的走势和2011年拥抱阳春三月,看那醉人的美景在北方,三月天可能还有一些寒气逼人,冬天还没有过去。可是在南方,很多地方也是春暖花开,小草发芽,众多的花儿把大地装扮的五彩缤纷,河边的垂柳已发芽。河边垂柳,每年这个时候是我们赏花看泰旅局处长转型视频博主云推介泰中文化盼跨境游复苏泰国国家旅游局成都办事处处长林美烔来自泰国宋卡府合艾市,在这座居住着很多华侨华人的城市出生成长,她从小便对中国文化元素并不陌生,且充满向往。2020年到成都就任后,林美烔很快便适应京城夜游指南,寻觅日落后的光影浪漫人们常说想了解一座城亲近一座城探寻城市的夜晚才是了解它的最好办法下面这些京城夜景打卡地各自彰显了北京不同角度的独特魅力在夜色中感受北京朝气蓬勃的气息和小北一起去看看吧夜游亮马河夜幕长安遗存杜陵杜陵是汉代第十位皇帝宣帝刘询的陵墓,位于潏浐两河之间的鸿固原上,此地古属杜县,因之得名,鸿固原却少有人知。近年来,在政府大水大绿工程的带动下,杜陵周边形成了万亩生态林,昔日的帝陵掩京城文化漫步这条胡同,原来藏着这么多故事!京城文化漫步在北京这座历史深厚的城市里,每一个院落都有很多故事,每一处历史文化街区都是一本关于城市的书,关于这座城市的故事也自然而然地渗透进文艺作品中。京城文化漫步栏目专注于发掘书束河夜谁还没点儿过往3七天六夜3hr回到住处,已近夜半十一点。思语留着门,打完招呼,三人便各回各的房间。慕城进屋后放下东西,径直走向阳台,他想看看那里适不适合拍组星轨。虽然是与晴雪同游,但摄影这点爱好也烂大街的阔腿裤,今春流行这样穿,不仅洋气显瘦,还有女人味阔腿裤是一件评价两极化的单品,有的人觉得它的版型设计过于普通,也因为受众广而显得烂大街,但不可否认,阔腿裤的版型也因为宽松而显得舒适,也是阔腿裤受欢迎的一大原因。如果你也想好好了解