Kratos技术系列|从Kratos设计看Go微服务工程实践.docx

上传人:安*** 文档编号:73269468 上传时间:2023-02-17 格式:DOCX 页数:18 大小:24.84KB
返回 下载 相关 举报
Kratos技术系列|从Kratos设计看Go微服务工程实践.docx_第1页
第1页 / 共18页
Kratos技术系列|从Kratos设计看Go微服务工程实践.docx_第2页
第2页 / 共18页
点击查看更多>>
资源描述

《Kratos技术系列|从Kratos设计看Go微服务工程实践.docx》由会员分享,可在线阅读,更多相关《Kratos技术系列|从Kratos设计看Go微服务工程实践.docx(18页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、Kratos技术系列从Kratos设计看Go微服务工程实践导读github/go-kratos/kratos以下简称Kratos是一套轻量级Go微效劳框架致力于提供完好的微效劳研发体验整合相关框架及周边工具后微效劳治理相关局部可对整体业务开发周期无感进而更加聚焦于业务交付。Kratos在设计之初就考虑到了高可扩展性组件化工程化标准化等。对每位开发者而言整套Kratos框架也是不错的学习仓库可以解析以及参考微效劳的技术积累以及经历。接下来我们从Protobuf、开放性、标准、依赖注入这4个点解析一下Kratos在Go微效劳工程领域的理论。曹国梁6年度Go微效劳研发经历腾讯云高级研发工程师Krat

2、osMaintainergRPC-gocontributor基于ProtocolBuffers(Protobuf)的生态在Kratos中API定义、gRPCService、HTTPService、恳求参数校验、错误定义、SwaggerAPIjson、应用效劳模版等都是基于ProtobufIDL来构建的举一个简单的helloworld.proto例子syntaxproto3packagehelloworld;importgoogle/api/annotations.protoimportprotoc-gen-openapiv2/options/annotations.protoimportval

3、idate/validate.protoimporterrors/errors.protooptiongo_packagegithub/go-kratos/kratos/examples/helloworld/helloworld/Thegreetingservicedefinition.serviceGreeter/SendsagreetingrpcSayHello(HelloRequest)returns(HelloReply)option(google.api.)/定义一个HTTPGET接口并且把name映射到HelloRequestget:/helloworld/name,;/添加AP

4、I接口描绘(swaggerapi)option(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_operation)description:这是SayHello接口;/Therequestmessagecontainingtheusersname.messageHelloRequest/增加name字段参数校验字符数需在1到16之间stringname1(validate.rules).stringmin_len:1,max_len:16;/TheresponsemessagecontainingthegreetingsmessageHe

5、lloReplystringmessageenumErrorReason/设置缺省错误码option(errors.default_code)500;/为某个错误枚举单独设置错误码USER_NOT_FOUND0(errors.code)404;CONTENT_MISSING1(errors.code)400;以上是一个简单的helloworld效劳定义的例子这里我们定义了一个Service叫Greeter给Greeter添加了一个SayHello的接口并根据googleapis标准给这个接口添加了Restful风格的HTTP接口定义然后还利用openapiv2添加了接口的SwaggerAPI描

6、绘同时还给恳求消息构造体HelloRequest中的name字段加上了参数校验最后我们在文件的末尾还定义了这个效劳可能返回的错误码。这时我们在终端中执行:kratosprotoclientapi/helloworld/helloworld.proto便可以生成以下文件由上我们看到Kraots脚手架工具帮我们一键生成了上面提到的才能。从这个例子中我们可以直观感受到使用使用Protobuf带来的开发效率的提升除此之外Kratos还有以下优点明晰做到了定义即文档定义即代码收敛统一将逻辑都收敛统一到一起通过代码生成工具来保证HTTPService、grpcService等功能具有一致的行为跨语言众所周

7、知Protobuf是跨语言的java、go、python、php、js、c等等主流语言都支持拥抱开源生态比方Kratos复用了google.api、protoc-gen-openapiv2、protoc-gen-validate等等一些犀利的Protobuf周边生态工具或者标准这比起自己造一个IDL的轮子要容易维护得多同时老的使用这些轮子的gRPC工程迁移本钱也更低开放性一个根底框架在设计的时候就要考虑将来的可扩展性那Kratos是怎么做的呢1.ServerTransport我们先看下效劳协议层的代码上面是KratosRPC效劳协议层的接口定义这里我们可以看到假如想要给Kratos新增一个新的

8、效劳协议只要实现Start()、Stop()、Endpoint()这几个方法即可。这样的设计解耦了应用以及效劳协议层的实现使得扩展效劳协议更加方便。从上图中我们可以看到App层无需关心底层效劳协议的实现只是一个容器管理好应用配置、效劳生命周期、加载顺序即可。2.Log我们再看一个Kratos日志模块的设计这里Kratos定义了一个日志输出接口Logger它的设计的非常简单-只用了一个方法、两个输入、一个输出。我们知道一个包暴露的接口越少越容易维护同时对使用以及实现方的心智负担更小扩展日志实现会变得更容易。但问题来了这个接口从功能上来讲似乎只能输出日志level以及固定的kvparis怎样能支持

9、更高级的功能比方输出callerstack、实时timestamp、contexttraceID这里我们定义了一个回调接口Valuer这个Valuer可以被当作key/valuepairs中的value被Append到日志里并被实时调用。我们看一下怎样给日志加时间戳的Valuer实现使用时只要在原始的logger上再append一个固定的key以及一个动态的valuer即可这里的With是一个Helperfunction里面new了一个新的logger也实现了Logger接口并将keyvaluepairs暂存在新的logger里等到Log方法被调用时再通过断言.(Valuer)的方式获取值并输

10、出给底层原始的logger。所以我们可以看到仅仅通过两个简单的接口一个Helperfunction的组合我们就实现了日志的大多数功能这样大大进步了可扩展性。实际上还有日志过滤、多日志源输出等功能也是通过组合使用这两接口来实现这里待下次共享再展开细讲。3.Tracing最后我们来看下Kratos的Tracing组件这里Kratos采用的是CNCF工程OpenTelemetry。OpenTelemetry在设计之初就考虑到了组件化以及高可扩展性其实现了OpenTracing以及W3CTraceContext的标准可以无缝对接zipkin、jaeger等主流开源tracing系统并且可以自定义Pro

11、pagator以及TraceProvider。通过otel.SetTracerProvider()我们可以轻易得交换Span的落地协议以及格式进而兼容老系统中的trace收集agent通过otel.SetTextMapPropagtor()我们可以交换Span在RPC中的Encoding协议进而可以以及老系统中的效劳相互调用时也能兼容。工程流程我们知道在工程理论的时候强标准以及约束往往比自由以及更多的选择更有优势那么在Go工程标准这块我这里主要介绍三块1.面向包的设计标准Go是一个面向包名设计的语言Package在Go程序中主要起到功能隔离的作用标准库就是很好的设计范例。Kratos也是可以按

12、包进展组织代码构造这里我们抽取Kratos根目录下主要几个Package包来看下/cmd:可以通过goinstall一键安装生成工具使用户更加方便地使用框架。/api:Kratos框架本身的暴露的接口定义/errors:统一的业务错误封装方便返回错误码以及业务原因。/config:支持多数据源方式进展配置合并铺平通过Atomic方式支热更配置。/internal存放对外不可见或不稳定的接口。/transport:效劳协议层HTTP/gRPC的抽象封装可以方便获取对应的接口信息。/middleware:中间件抽象接口主要跟transport以及service之间的桥梁适配器。/third_par

13、ty:第三方外部的依赖可以看到Kratos的包命名明晰简短按功能进展划分每个包具有唯一的职责。在设计包时我们还需要考虑到以下几点包的设计必须以使用者为中心直观且易于使用包的命名必须旨在描绘它提供的内容假如包的名称不能立即暗示这一点那么它可能包含一组零散的功能。包的目的是为特定问题域而提供的为了有目的包必须提供而不是包含。包不能成为不同问题域的聚合地随着时间的推移它将影响工程的简洁以及重构、适应、扩展以及别离的才能。高便携性尽量减少依赖其他代码库一个包与其它包依赖越少一个包的可重用性就越高。不能成为单点依赖当包被单一的依赖点时就像一个公共包common会给工程带来很高的耦合性。2.配置首先我们来

14、看下常见的根底框架是怎么初始化配置的这是Go标准库HTTPServer配置初始化的例子但是这样做会有如下几个问题.Server由于是一个取址引用里面的参数可能会被外部运行时修改这种运行时修改带来的危害是不可把控的。无法区分nil以及0值当里面的参数值为0的时候不知道是用户未设置还是就是被设置成了0。难以分辨必传以及选传参数只能通过文档讲明来隐式约定没有强约束力。那么Kraots是怎么解决这些问题的呢答案就是FunctionalOptions。我们看下transport/client.go的代码Client.go中定义了一个回调函数ClientOption该函数承受一个定义了一个存放实际配置的未

15、导出构造体clientOptions的指针然后我们在NewClient的时候使用可变参数进展传递然后再初始化函数内部通过for循环调用修改相关的配置。这么做有这么几个好处由于clientOptions构造体是未导出的那么就不存在被外部修改的可能。可以区分0值以及未设置首先我们在newclientOptions时会设置默认参数那么假如外部没有传递相应的Option就不会修改这个默认参数。必选参数显示定义可选值那么通过Go可变参数进展传递很好的区分必传以及选传。3.Error标准Kratos为微效劳提供了统一的Error模型Code用作外部展示以及初步判断效劳端无需定义大量全局唯一的XXX_NOT

16、_FOUND而是使用一个标准Code.NOT_FOUND错误代码并告诉客户端找不到某个资源。错误空间变小降低了文档的复杂性在客户端库中提供了更好的惯用映射并降低了客户端的逻辑复杂性。同时这种标准的大类Code的存在也对外部的观测系统更友好比方可以通过分析NginxAccessLog中的HTTPStatusCode来做效劳端监控以及告警。Reason是详细的错误原因可以用来更详细的错误断定。每个微效劳都会定义自己Reason那么要保持全局唯一就需要加上领域前缀比方User_XXX。Message错误信息可以帮助用户轻松快捷地理解以及解决API错误Metadata中那么可以存放一些标准的错误详情比

17、方retryInfo、errorstack等这种强迫标准防止了开发人员直接透传Go的error进而导致一些敏感信息泄露。接下来我们看下Error构造体还实现了哪些接口实现了GRPCStatus()*status.Status接口这样就实现了从statuscode到grpcstatuscode的转换这样KratosError可以被gRPC直接转成google.rpc.Status传递出去。实现了标准库errors包的Is(error)bool接口这样使用者可以直接调用errors.Is()来比拟两个erorr中的reason是否相等防止了使用来直接判断error是否相等这种错误姿势。依赖注入依赖

18、注入(DependencyInjection)可以理解为一种代码的构造形式按照这样的方式来写可以让你的代码更加容易维护一般在Java的工程中见到的比拟多。依赖注入初看起来比拟违背直觉那么为什么Go也需要依赖注入假设我们要实现一个用户访问计数的功能。我们先看看不使用依赖注入的工程代码typeServicestructredisCli*redis.Clientfunc(s*Service)AddUserCount(ctxcontext.Context)/dosomebusinesslogics.redisCli.Incr(ctx,user_count)funcNewService(cfg*redi

19、s.Options)*ServicereturnServiceredisCli:redis.NewClient(cfg)这种方式比拟常见在工程刚开场或规模小的时候没什么问题但我们假如考虑下面这些因素Redis是根底组件往往会在工程的很多地方被依赖那么假如哪天我们想整体修改redissdk的甚至想把redis整体交换成mysql时需要在每个被用到的地方都进展修改耗时耗力还容易出错。很难对App这个类写单元测试因为我们需要创立一个真实的redis.Client。使用依赖注入改造后的ServicetypeDataSourceinterfaceIncr(context.Context,string)t

20、ypeServicestructdataSourceDataSourcefunc(s*Service)AddUserCount(ctxcontext.Context)/dosomebusinesslogics.dataSource.Incr(ctx,user_count)funcNewService(dsDataSource)*ServicereturnServicedataSource:ds上面代码中我们把*redis.Client实体交换成了一个DataSource接口同时不控制dataSource的创立以及销毁把dataSource生命周期控制权交给了上层来处理以上操作有三个主要原因因为

21、Service层已不再关心dataSource的创立以及销毁这样当我们需要修改dataSource实现的时候只要在上层统一修改即可无需在各个被依赖的地方一一修改。因为依赖的是一个接口我们写单元测试的时候只要传递一个mock后的Datasource实现即可。这里dataSource这个根底组件不再被会到处创立可以做到复用一个单例节省资源开销。Go的依赖注入框架有两类一类是通过反射在运行时进展依赖注入典型代表是uber开源的dig另外一类是通过generate进展代码生成典型代表是Google开源的wire。使用dig功能会强大一些但是缺点就是错误只能在运行时才能发现这样假如不小心的话可能会导致一

22、些隐藏的bug出现。使用wire的缺点就是功能限制多一些但是好处就是编译的时候就可以发现问题并且生成的代码其实以及我们自己手写相关代码差不过多更符合直觉心智负担更小。所以Kratos更加推荐wireKratos的默认工程模板中kratos-layout也正是使用了google/wire进展依赖注入。我们来看下wire使用方式我们首先要定义一个ProviderSet这个Set会返回构建依赖关系所需的组件Provider。如下所示Provider往往是一些简单的工厂函数这些函数不会太复杂typeRedisSourcestructredisCli*redis.Client/RedisSource实现

23、了Datasource的Incr接口func(ds*RedisSource)Incr(ctxcontext.Context,keystring)ds.redisCli.Incr(ctx,key)/构建实现了DataSource接口的ProviderfuncNewRedisSource(db*redis.Client)*RedisSourcereturnRedisSourceredisCli:db/构建*redis.Client的ProviderfuncNewRedis(cfg*redis.Options)*redis.Clientreturnredis.NewClient(cfg)/这是一个P

24、rovider的集合告诉wire这个包提供了哪些ProvidervarProviderSetwire.NewSet(NewRedis,NewRedisSource)接着我们要在应用启动处新建一个wire.go文件并定义InjectorInjctor会分析依赖关系并将Provider串联起来构建出最终的Service/buildwireinjectfuncinitService(cfg*redis.Options)*service.Servicepanic(wire.Build(redisSource.ProviderSet,/使用wire.Bind将Struct以及接口进展绑定了表示这个构造体

25、实现了这个接口wire.Bind(new(data.DataSource),new(*redisSource.RedisSource),service.NewService),)最后执行wire.后自动生成的代码如下/go:generategorungithub/google/wire/cmd/wire/build!wireinjectfuncinitService(cfg*redis.Options)*service.Serviceclient:redis2.NewRedis(cfg)redisSource:redis2.NewRedisSource(client)serviceServic

26、e:service.NewService(redisSource)returnserviceService由此我们可以看到只要定义好组件初始化的Provider函数还有把这些Provider组装在一起的Injector就可以直接生成初始化链路代码了上手还是相对简单的生成的代码所见即所得容易Debug。综上可见Kratos是一款凝结了开源社区力量和Go同学们大量微效劳工程理论后诞生的一款微效劳框架。如今腾讯云微效劳治理治理平台(微效劳平台TSF)也已支持Kratos框架给Kratos赋予了更多企业级效劳治理才能、提供多维度效劳如应用生命周期托管、一键上云、私有化部署、多语言发布。 (扫描二维码查

27、看Go接入TSF腾讯云文档免费体验馆消息队列CKafka分布式、高吞吐量、高可扩展性的消息效劳具备数据压缩、同时支持离线以及实时数据处理等优点。扫码即可免费体验免费体验途径云产品体验-根底-消息队列CKafka消息队列TDMQ一款基于Apache顶级开源工程Pulsar自研的金融级分布式消息中间件。其计算与存储别离的架构设计使得它具备极好的云原生以及Serverless特性用户按量使用无需关心底层资源。扫码点击“立即使用即可免费体验微效劳平台TSF稳定、高性能的技术中台。一个围绕着应用以及微效劳的PaaS平台提供给用全生命周期管理、数据化运营、立体化监控以及效劳治理等功能。TSF拥抱Sprin

28、gCloud、ServiceMesh微效劳框架帮助企业客户解决传统集中式架构转型的困难打造大规模高可用的分布式系统架构实现业务、产品的快速落地。扫码点击“免费体验即可免费体验微效劳引擎TSE高效、稳定的注册中心托管助力您快速实现微效劳架构转型。扫码点击“立即申请即可免费体验弹性微效劳TEM面向微效劳应用的ServerlessPaaS平台实现资源Serverless化与微效劳架构的完美结合提供一整套开箱即用的微效劳解决方案。弹性微效劳帮助用户创立以及管理云资源并提供秒级弹性伸缩用户可按需使用、按量付费极大程度上帮用户节约运维以及资源本钱。让用户充分聚焦企业核心业务本身助力业务成功。扫码点击“立即申请即可免费体验往期推荐?【阵容扩大】三位腾讯Maintainer参加ApachePulsar生态工程RocketMQ-on-Palsar?扫描下方二维码关注本公众号解析更多微效劳、消息队列的相关信息解锁超多鹅厂周边戳原文解析更多腾讯微效劳平台相关信息

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 技术资料 > 工程图纸

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁