From dff8f175d96e832fb521f13246cce14399aefcdb Mon Sep 17 00:00:00 2001 From: copy rogers <40619032+rogerogers@users.noreply.github.com> Date: Wed, 8 May 2024 11:35:39 +0800 Subject: [PATCH] style: prettier lint fix (#1069) Signed-off-by: rogerogers --- content/en/blog/_index.md | 2 - content/en/blog/news/1st_RPCKitex/index.md | 10 +- .../index.md | 33 +- ...in_Microservice_Architecture_with_Kitex.md | 110 +- .../index.md | 42 +- content/en/blog/news/Hertz_Benchmark/index.md | 29 +- .../en/blog/news/Hertz_Open_Source/index.md | 37 +- .../blog/news/Introducing CloudWeGo/index.md | 11 +- .../Kitex_Proxyless_OpenTelemetry/index.md | 53 +- .../Kitex_perf_optimize_practices/index.md | 216 ++-- .../news/Kitex_performance_testing/index.md | 11 +- .../index.md | 78 +- .../index.md | 27 +- content/en/blog/news/_index.md | 2 - .../news/bytedance_gonet_practice/index.md | 3 +- .../en/blog/news/open_source_volo/index.md | 11 +- .../en/blog/releases/Hertz/release-v010.md | 35 +- .../en/blog/releases/Hertz/release-v020.md | 39 +- .../en/blog/releases/Hertz/release-v030.md | 47 +- .../en/blog/releases/Hertz/release-v032.md | 15 +- .../en/blog/releases/Hertz/release-v040.md | 49 +- .../en/blog/releases/Hertz/release-v050.md | 9 +- .../en/blog/releases/Hertz/release-v060.md | 62 +- .../en/blog/releases/Hertz/release-v070.md | 32 +- .../en/blog/releases/Hertz/release-v080.md | 12 +- content/en/blog/releases/Kitex/_index.md | 2 +- .../en/blog/releases/Kitex/release-v001.md | 3 +- .../en/blog/releases/Kitex/release-v002.md | 1 - .../en/blog/releases/Kitex/release-v003.md | 3 +- .../en/blog/releases/Kitex/release-v004.md | 1 - .../en/blog/releases/Kitex/release-v005.md | 1 - .../en/blog/releases/Kitex/release-v008.md | 20 +- .../en/blog/releases/Kitex/release-v010.md | 70 +- .../en/blog/releases/Kitex/release-v012.md | 9 +- .../en/blog/releases/Kitex/release-v013.md | 13 +- .../en/blog/releases/Kitex/release-v014.md | 20 +- .../en/blog/releases/Kitex/release-v020.md | 21 +- .../en/blog/releases/Kitex/release-v021.md | 27 +- .../en/blog/releases/Kitex/release-v030.md | 45 +- .../en/blog/releases/Kitex/release-v032.md | 43 +- .../en/blog/releases/Kitex/release-v040.md | 73 +- .../en/blog/releases/Kitex/release-v043.md | 75 +- .../en/blog/releases/Kitex/release-v050.md | 12 +- .../en/blog/releases/Kitex/release-v052.md | 47 +- .../en/blog/releases/Kitex/release-v060.md | 9 +- .../en/blog/releases/Kitex/release-v070.md | 11 +- .../en/blog/releases/Kitex/release-v072.md | 14 +- .../en/blog/releases/Kitex/release-v080.md | 33 +- .../en/blog/releases/Kitex/release-v090.md | 14 +- content/en/blog/releases/Volo/_index.md | 1 - .../en/blog/releases/Volo/release-v0100.md | 7 +- content/en/blog/releases/Volo/release-v020.md | 21 +- content/en/blog/releases/Volo/release-v021.md | 11 +- content/en/blog/releases/Volo/release-v032.md | 4 +- content/en/blog/releases/Volo/release-v041.md | 4 +- content/en/blog/releases/Volo/release-v080.md | 7 +- content/en/blog/releases/Volo/release-v090.md | 5 +- content/en/blog/releases/_index.md | 3 - content/en/community/_index.md | 5 +- content/en/cooperation/_index.md | 13 +- content/en/cooperation/feishu.md | 11 +- content/en/cooperation/huaxingsec.md | 42 +- content/en/cooperation/semir.md | 2 + content/en/docs/_index.md | 4 +- content/en/docs/cwgo/_index.md | 6 +- content/en/docs/cwgo/tutorials/_index.md | 1 - .../docs/cwgo/tutorials/api-list/commands.md | 27 +- .../docs/cwgo/tutorials/api-list/example.md | 2 +- .../en/docs/cwgo/tutorials/client/command.md | 6 +- .../docs/cwgo/tutorials/client/example_pb.md | 6 +- .../cwgo/tutorials/client/example_thrift.md | 4 +- content/en/docs/cwgo/tutorials/db/_index.md | 4 +- .../en/docs/cwgo/tutorials/doc/commands.md | 22 +- .../docs/cwgo/tutorials/doc/example_thrift.md | 4 +- content/en/docs/cwgo/tutorials/doc/layout.md | 4 +- .../en/docs/cwgo/tutorials/doc/usage_rule.md | 10 +- .../en/docs/cwgo/tutorials/server/command.md | 4 +- .../docs/cwgo/tutorials/server/example_pb.md | 4 +- .../cwgo/tutorials/server/example_thrift.md | 4 +- content/en/docs/hertz/_index.md | 6 +- content/en/docs/hertz/faq/_index.md | 16 +- .../en/docs/hertz/getting-started/_index.md | 11 +- content/en/docs/hertz/overview/_index.md | 12 +- content/en/docs/hertz/reference/_index.md | 1 - content/en/docs/hertz/reference/config.md | 119 +- content/en/docs/hertz/reference/version.md | 1 - content/en/docs/hertz/tutorials/_index.md | 13 +- .../hertz/tutorials/basic-feature/_index.md | 24 +- .../hertz/tutorials/basic-feature/adaptor.md | 7 +- .../basic-feature/binding-and-validate.md | 40 +- .../hertz/tutorials/basic-feature/client.md | 76 +- .../tutorials/basic-feature/constants.md | 12 +- .../tutorials/basic-feature/context/_index.md | 11 +- .../basic-feature/context/request.md | 436 +++---- .../basic-feature/context/response.md | 145 +-- .../hertz/tutorials/basic-feature/engine.md | 317 +++-- .../tutorials/basic-feature/error-handle.md | 33 +- .../basic-feature/graceful-shutdown.md | 1 - .../hertz/tutorials/basic-feature/hooks.md | 7 +- .../hertz/tutorials/basic-feature/json.md | 10 +- .../basic-feature/middleware/_index.md | 28 +- .../basic-feature/middleware/basic-auth.md | 5 +- .../basic-feature/middleware/cache.md | 25 +- .../basic-feature/middleware/casbin.md | 106 +- .../basic-feature/middleware/cors.md | 7 +- .../basic-feature/middleware/csrf.md | 5 +- .../basic-feature/middleware/etag.md | 13 +- .../basic-feature/middleware/gzip.md | 1 - .../basic-feature/middleware/i18n.md | 19 +- .../tutorials/basic-feature/middleware/jwt.md | 3 +- .../basic-feature/middleware/keyauth.md | 1 - .../basic-feature/middleware/paseto.md | 28 +- .../basic-feature/middleware/pprof.md | 12 +- .../basic-feature/middleware/recovery.md | 3 +- .../basic-feature/middleware/requestid.md | 3 +- .../basic-feature/middleware/secure.md | 6 +- .../basic-feature/middleware/sentry.md | 17 +- .../basic-feature/middleware/session.md | 3 +- .../basic-feature/middleware/swagger.md | 22 +- .../tutorials/basic-feature/network-lib.md | 7 +- .../basic-feature/protocol/_index.md | 3 +- .../tutorials/basic-feature/protocol/http2.md | 18 +- .../tutorials/basic-feature/protocol/http3.md | 19 +- .../tutorials/basic-feature/protocol/sse.md | 29 +- .../tutorials/basic-feature/protocol/tls.md | 14 +- .../basic-feature/protocol/websocket.md | 20 +- .../hertz/tutorials/basic-feature/proxy.md | 15 +- .../hertz/tutorials/basic-feature/render.md | 26 +- .../hertz/tutorials/basic-feature/retry.md | 49 +- .../hertz/tutorials/basic-feature/route.md | 64 +- .../tutorials/basic-feature/unit-test.md | 19 +- .../en/docs/hertz/tutorials/example/_index.md | 43 +- .../hertz/tutorials/framework-exten/_index.md | 12 +- .../tutorials/framework-exten/log/_index.md | 3 +- .../tutorials/framework-exten/log/logrus.md | 9 +- .../tutorials/framework-exten/log/slog.md | 9 +- .../tutorials/framework-exten/log/zap.md | 6 +- .../tutorials/framework-exten/log/zerolog.md | 18 +- .../tutorials/framework-exten/monitor.md | 1 - .../tutorials/framework-exten/network-lib.md | 15 +- .../tutorials/framework-exten/protocol.md | 3 +- .../framework-exten/response_writer.md | 7 +- .../framework-exten/service_discovery.md | 8 +- .../hertz/tutorials/observability/_index.md | 1 - .../docs/hertz/tutorials/observability/log.md | 1 - .../tutorials/observability/monitoring.md | 1 - .../tutorials/service-governance/_index.md | 4 +- .../service_discovery/_index.md | 23 +- .../service_discovery/consul.md | 412 +++---- .../service_discovery/etcd.md | 792 ++++++------ .../service_discovery/eureka.md | 536 ++++----- .../service_discovery/nacos.md | 774 ++++++------ .../service_discovery/polaris.md | 346 +++--- .../service_discovery/redis.md | 1062 ++++++++--------- .../service_discovery/servicecomb.md | 940 +++++++-------- .../service_discovery/zookeeper.md | 426 +++---- .../tutorials/service-migration/_index.md | 1 - .../en/docs/hertz/tutorials/toolkit/_index.md | 1 - .../hertz/tutorials/toolkit/annotation.md | 13 +- .../docs/hertz/tutorials/toolkit/cautions.md | 63 +- .../docs/hertz/tutorials/toolkit/command.md | 21 +- .../docs/hertz/tutorials/toolkit/install.md | 15 +- .../en/docs/hertz/tutorials/toolkit/layout.md | 4 +- .../tutorials/toolkit/more-feature/_index.md | 3 +- .../toolkit/more-feature/api_none.md | 3 +- .../tutorials/toolkit/more-feature/client.md | 33 +- .../tutorials/toolkit/more-feature/plugin.md | 2 +- .../toolkit/more-feature/template.md | 328 ++--- .../hertz/tutorials/toolkit/usage-protobuf.md | 8 +- .../hertz/tutorials/toolkit/usage-thrift.md | 6 +- .../Integration Testing/_index.md | 1 - .../Integration Testing/debug_efficiently.md | 11 +- .../Integration Testing/mock_client.md | 5 +- .../kitex/Best Practice/usage_attention.md | 6 +- content/en/docs/kitex/FAQ/_index.md | 45 +- .../en/docs/kitex/Getting started/_index.md | 1 - .../en/docs/kitex/Getting started/examples.md | 3 +- .../kitex/Getting started/pre-knowledge.md | 34 +- .../kitex/Getting started/prerequisite.md | 2 +- .../docs/kitex/Getting started/quick_start.md | 11 +- .../en/docs/kitex/Getting started/tutorial.md | 20 +- content/en/docs/kitex/Overview/_index.md | 12 +- content/en/docs/kitex/Reference/_index.md | 3 +- content/en/docs/kitex/Reference/exception.md | 3 +- content/en/docs/kitex/Tutorials/_index.md | 2 - .../kitex/Tutorials/advanced-feature/GLS.md | 4 +- .../Tutorials/advanced-feature/_index.md | 1 - .../advanced-feature/codec_frugal.md | 47 +- .../advanced-feature/error_handler.md | 12 +- .../generic-call/basic_usage.md | 2 +- .../generic-call/generic-call-reflection.md | 21 +- .../thrift_idl_annotation_standards.md | 68 +- .../Tutorials/advanced-feature/metainfo.md | 21 +- .../advanced-feature/multi_service.md | 15 +- .../Tutorials/advanced-feature/profiler.md | 2 +- .../kitex/Tutorials/advanced-feature/xds.md | 40 +- .../kitex/Tutorials/basic-feature/_index.md | 3 +- .../basic-feature/acquire_rpcinfo.md | 20 +- .../Tutorials/basic-feature/bizstatuserr.md | 26 +- .../basic-feature/connection_type.md | 12 +- .../Tutorials/basic-feature/message_type.md | 20 +- .../basic-feature/protocol/_index.md | 1 - .../protocol/serialization-protocol/binary.md | 2 +- .../serialization-protocol/hessian2.md | 2 +- .../serialization-protocol/protobuf.md | 2 +- .../protocol/transport-streaming/_index.md | 1 - .../transport-streaming/thrift_streaming.md | 139 ++- .../Tutorials/basic-feature/visit_directly.md | 2 + .../Tutorials/basic-feature/warming_up.md | 3 +- .../docs/kitex/Tutorials/code-gen/_index.md | 1 - .../kitex/Tutorials/code-gen/idl_trimmer.md | 66 +- .../Tutorials/code-gen/template_extension.md | 38 +- .../kitex/Tutorials/code-gen/validator.md | 14 +- .../kitex/Tutorials/framework-exten/_index.md | 1 - .../kitex/Tutorials/framework-exten/codec.md | 4 +- .../Tutorials/framework-exten/diagnosis.md | 3 - .../Tutorials/framework-exten/middleware.md | 32 +- .../Tutorials/framework-exten/registry.md | 7 +- .../framework-exten/service_discovery.md | 9 +- .../kitex/Tutorials/framework-exten/suite.md | 5 + .../framework-exten/trans_pipeline.md | 27 +- .../Tutorials/framework-exten/transmeta.md | 2 - .../Tutorials/framework-exten/transport.md | 4 +- .../kitex/Tutorials/observability/_index.md | 1 - .../observability/instrumentation.md | 6 +- .../Tutorials/observability/monitoring.md | 32 +- .../en/docs/kitex/Tutorials/options/_index.md | 1 - .../kitex/Tutorials/options/call_options.md | 12 - .../kitex/Tutorials/options/client_options.md | 111 +- .../kitex/Tutorials/options/server_options.md | 92 +- .../Tutorials/service-governance/_index.md | 3 +- .../service-governance/circuitbreaker.md | 17 +- .../config-center/_index.md | 6 +- .../config-center/apollo.md | 105 +- .../config-center/consul.md | 24 +- .../service-governance/config-center/etcd.md | 113 +- .../service-governance/config-center/file.md | 233 ++-- .../service-governance/config-center/nacos.md | 136 ++- .../config-center/zookeeper.md | 29 +- .../Tutorials/service-governance/fallback.md | 23 +- .../Tutorials/service-governance/limiting.md | 1 + .../service-governance/loadbalance.md | 8 +- .../Tutorials/service-governance/retry.md | 50 +- .../service_discovery/consul.md | 4 +- .../service_discovery/etcd.md | 15 +- .../service_discovery/eureka.md | 4 +- .../service_discovery/nacos.md | 29 +- .../service_discovery/polaris.md | 4 +- .../service_discovery/rule-based.md | 41 +- .../Tutorials/service-governance/timeout.md | 26 +- content/en/docs/kitex/_index.md | 6 +- .../en/docs/netpoll/Common Usage/_index.md | 26 +- .../en/docs/netpoll/Getting started/_index.md | 14 +- content/en/docs/netpoll/Overview/_index.md | 47 +- content/en/docs/netpoll/_index.md | 6 +- content/en/docs/volo/_index.md | 6 +- content/en/docs/volo/faq/_index.md | 6 +- content/en/docs/volo/guide/config.md | 33 +- content/en/docs/volo/guide/discovery_lb.md | 2 +- content/en/docs/volo/guide/metadata.md | 2 - content/en/docs/volo/guide/observability.md | 1 - content/en/docs/volo/guide/with_callopt.md | 2 - content/en/docs/volo/motore/_index.md | 7 +- content/en/docs/volo/overview/_index.md | 1 - content/en/docs/volo/pilota/_index.md | 6 +- content/en/docs/volo/volo-grpc/_index.md | 2 - content/en/docs/volo/volo-thrift/_index.md | 1 - content/en/search.md | 2 - content/en/security/_index.md | 6 +- .../security/safety-bulletin/detail/_index.md | 1 - .../detail/cloudwego-sa-2022-1/index.md | 7 + .../detail/cloudwego-sa-2022-2/index.md | 6 + content/zh/blog/_index.md | 2 - content/zh/blog/news/1st_RPCKitex/index.md | 40 +- content/zh/blog/news/1st_httpHertz/index.md | 72 +- .../blog/news/2nd_Kitex_retrospect/index.md | 56 +- .../CloudWeGo_Usability_Construction/index.md | 18 +- content/zh/blog/news/Hertz_Benchmark/index.md | 27 +- .../zh/blog/news/Hertz_Open_Source/index.md | 24 +- .../news/Hertz_Stream_Based_Design/index.md | 32 +- .../news/Kitex_Dubbo_interoperate/index.md | 144 ++- .../Kitex_Proxyless_OpenTelemetry/index.md | 79 +- .../Kitex_perf_optimize_practices/index.md | 119 +- .../news/Kitex_performance_testing/index.md | 35 +- content/zh/blog/news/Rust_or_Go/index.md | 64 +- content/zh/blog/news/_index.md | 2 - .../zh/blog/news/open_source_volo/index.md | 10 +- .../zh/blog/releases/Hertz/release-v010.md | 29 +- .../zh/blog/releases/Hertz/release-v020.md | 39 +- .../zh/blog/releases/Hertz/release-v030.md | 47 +- .../zh/blog/releases/Hertz/release-v032.md | 15 +- .../zh/blog/releases/Hertz/release-v040.md | 49 +- .../zh/blog/releases/Hertz/release-v050.md | 24 +- .../zh/blog/releases/Hertz/release-v060.md | 54 +- .../zh/blog/releases/Hertz/release-v070.md | 33 +- .../zh/blog/releases/Hertz/release-v080.md | 16 +- content/zh/blog/releases/Kitex/_index.md | 2 +- .../zh/blog/releases/Kitex/release-v001.md | 3 +- .../zh/blog/releases/Kitex/release-v002.md | 2 - .../zh/blog/releases/Kitex/release-v003.md | 4 +- .../zh/blog/releases/Kitex/release-v004.md | 4 +- .../zh/blog/releases/Kitex/release-v005.md | 1 - .../zh/blog/releases/Kitex/release-v008.md | 16 +- .../zh/blog/releases/Kitex/release-v010.md | 86 +- .../zh/blog/releases/Kitex/release-v012.md | 9 +- .../zh/blog/releases/Kitex/release-v013.md | 13 +- .../zh/blog/releases/Kitex/release-v014.md | 20 +- .../zh/blog/releases/Kitex/release-v020.md | 23 +- .../zh/blog/releases/Kitex/release-v021.md | 27 +- .../zh/blog/releases/Kitex/release-v030.md | 45 +- .../zh/blog/releases/Kitex/release-v032.md | 44 +- .../zh/blog/releases/Kitex/release-v040.md | 69 +- .../zh/blog/releases/Kitex/release-v043.md | 76 +- .../zh/blog/releases/Kitex/release-v050.md | 15 +- .../zh/blog/releases/Kitex/release-v052.md | 48 +- .../zh/blog/releases/Kitex/release-v060.md | 9 +- .../zh/blog/releases/Kitex/release-v070.md | 8 +- .../zh/blog/releases/Kitex/release-v072.md | 15 +- .../zh/blog/releases/Kitex/release-v080.md | 31 +- .../zh/blog/releases/Kitex/release-v090.md | 12 +- content/zh/blog/releases/Volo/_index.md | 1 - .../zh/blog/releases/Volo/release-v0100.md | 7 +- content/zh/blog/releases/Volo/release-v020.md | 21 +- content/zh/blog/releases/Volo/release-v021.md | 11 +- content/zh/blog/releases/Volo/release-v041.md | 4 +- content/zh/blog/releases/Volo/release-v050.md | 4 +- content/zh/blog/releases/Volo/release-v054.md | 24 +- content/zh/blog/releases/Volo/release-v080.md | 7 +- content/zh/blog/releases/Volo/release-v090.md | 5 +- content/zh/blog/releases/_index.md | 3 - .../meeting_notes/2022-02-25/_index.md | 7 +- .../meeting_notes/2022-03-11/_index.md | 42 +- .../meeting_notes/2022-03-25/_index.md | 6 +- .../meeting_notes/2022-04-08/_index.md | 14 +- .../meeting_notes/2022-04-21/_index.md | 11 +- .../meeting_notes/2022-05-19/_index.md | 9 +- .../meeting_notes/2022-06-02/_index.md | 11 +- .../meeting_notes/2022-06-16/_index.md | 19 +- .../meeting_notes/2022-06-30/_index.md | 35 +- .../meeting_notes/2022-07-14/_index.md | 51 +- .../meeting_notes/2022-07-28/_index.md | 15 +- .../meeting_notes/2022-08-11/_index.md | 8 +- .../meeting_notes/2022-09-08/_index.md | 1 - .../meeting_notes/2022-09-22/_index.md | 11 +- .../meeting_notes/2022-10-20/_index.md | 6 +- .../meeting_notes/2022-11-03/_index.md | 9 +- .../zh/community/past_activities/_index.md | 6 +- .../zh/community/weekly_report/10th/_index.md | 1 + .../zh/community/weekly_report/11th/_index.md | 1 + .../zh/community/weekly_report/12th/_index.md | 2 - .../zh/community/weekly_report/13th/_index.md | 2 - .../zh/community/weekly_report/14th/_index.md | 3 - .../zh/community/weekly_report/15th/_index.md | 3 - .../zh/community/weekly_report/16th/_index.md | 1 - .../zh/community/weekly_report/17th/_index.md | 1 - .../zh/community/weekly_report/18th/_index.md | 1 - .../zh/community/weekly_report/19th/_index.md | 1 - .../zh/community/weekly_report/20th/_index.md | 1 - .../zh/community/weekly_report/21th/_index.md | 1 - .../zh/community/weekly_report/5th/_index.md | 1 + .../zh/community/weekly_report/6th/_index.md | 1 + .../zh/community/weekly_report/7th/_index.md | 1 + .../zh/community/weekly_report/8th/_index.md | 1 + .../zh/community/weekly_report/9th/_index.md | 1 + content/zh/community/weekly_report/_index.md | 1 - content/zh/cooperation/_index.md | 4 +- content/zh/cooperation/feishu.md | 5 + content/zh/cooperation/foundersc.md | 149 ++- content/zh/cooperation/huaxingsec.md | 21 +- content/zh/cooperation/interface_testing.md | 50 +- content/zh/cooperation/semir.md | 2 + content/zh/cooperation/tanwan.md | 75 +- content/zh/css/docs.css | 5 +- content/zh/docs/_index.md | 1 - content/zh/docs/cwgo/_index.md | 6 +- content/zh/docs/cwgo/tutorials/_index.md | 1 - .../docs/cwgo/tutorials/api-list/cautions.md | 2 +- .../docs/cwgo/tutorials/api-list/commands.md | 27 +- .../docs/cwgo/tutorials/api-list/example.md | 2 +- .../zh/docs/cwgo/tutorials/client/command.md | 6 +- .../docs/cwgo/tutorials/client/example_pb.md | 4 +- .../cwgo/tutorials/client/example_thrift.md | 4 +- content/zh/docs/cwgo/tutorials/db/_index.md | 4 +- .../zh/docs/cwgo/tutorials/doc/commands.md | 22 +- .../docs/cwgo/tutorials/doc/example_thrift.md | 4 +- content/zh/docs/cwgo/tutorials/doc/layout.md | 4 +- .../zh/docs/cwgo/tutorials/doc/usage_rule.md | 46 +- .../zh/docs/cwgo/tutorials/server/_index.md | 1 - .../zh/docs/cwgo/tutorials/server/command.md | 4 +- .../docs/cwgo/tutorials/server/example_pb.md | 4 +- .../cwgo/tutorials/server/example_thrift.md | 4 +- .../tutorials/templete-extension/_index.md | 4 +- content/zh/docs/hertz/_index.md | 6 +- content/zh/docs/hertz/faq/_index.md | 12 +- .../zh/docs/hertz/getting-started/_index.md | 25 +- content/zh/docs/hertz/overview/_index.md | 7 +- content/zh/docs/hertz/reference/_index.md | 1 - content/zh/docs/hertz/reference/config.md | 119 +- content/zh/docs/hertz/reference/version.md | 1 - content/zh/docs/hertz/tutorials/_index.md | 13 +- .../hertz/tutorials/basic-feature/_index.md | 24 +- .../hertz/tutorials/basic-feature/adaptor.md | 17 +- .../basic-feature/binding-and-validate.md | 73 +- .../hertz/tutorials/basic-feature/client.md | 69 +- .../tutorials/basic-feature/constants.md | 14 +- .../basic-feature/context/request.md | 436 +++---- .../basic-feature/context/response.md | 137 +-- .../hertz/tutorials/basic-feature/engine.md | 335 +++--- .../tutorials/basic-feature/error-handle.md | 21 +- .../basic-feature/graceful-shutdown.md | 1 - .../hertz/tutorials/basic-feature/hooks.md | 1 - .../hertz/tutorials/basic-feature/json.md | 2 +- .../basic-feature/middleware/_index.md | 9 +- .../basic-feature/middleware/basic-auth.md | 9 +- .../basic-feature/middleware/cache.md | 25 +- .../basic-feature/middleware/casbin.md | 96 +- .../basic-feature/middleware/cors.md | 29 +- .../basic-feature/middleware/csrf.md | 24 +- .../basic-feature/middleware/etag.md | 12 +- .../basic-feature/middleware/gzip.md | 2 - .../basic-feature/middleware/i18n.md | 15 +- .../tutorials/basic-feature/middleware/jwt.md | 61 +- .../basic-feature/middleware/keyauth.md | 1 - .../basic-feature/middleware/paseto.md | 32 +- .../basic-feature/middleware/pprof.md | 12 +- .../basic-feature/middleware/recovery.md | 1 - .../basic-feature/middleware/requestid.md | 11 +- .../basic-feature/middleware/secure.md | 22 +- .../basic-feature/middleware/sentry.md | 15 +- .../basic-feature/middleware/session.md | 21 +- .../basic-feature/middleware/swagger.md | 25 +- .../tutorials/basic-feature/network-lib.md | 7 +- .../basic-feature/protocol/_index.md | 5 +- .../tutorials/basic-feature/protocol/http2.md | 28 +- .../tutorials/basic-feature/protocol/http3.md | 19 +- .../tutorials/basic-feature/protocol/sse.md | 23 +- .../tutorials/basic-feature/protocol/tls.md | 43 +- .../basic-feature/protocol/websocket.md | 22 +- .../hertz/tutorials/basic-feature/proxy.md | 29 +- .../hertz/tutorials/basic-feature/render.md | 15 +- .../hertz/tutorials/basic-feature/retry.md | 43 +- .../hertz/tutorials/basic-feature/route.md | 64 +- .../tutorials/basic-feature/unit-test.md | 19 +- .../zh/docs/hertz/tutorials/example/_index.md | 42 +- .../hertz/tutorials/framework-exten/_index.md | 12 +- .../tutorials/framework-exten/log/_index.md | 4 +- .../tutorials/framework-exten/log/logrus.md | 6 +- .../tutorials/framework-exten/log/slog.md | 9 +- .../tutorials/framework-exten/log/zap.md | 7 +- .../tutorials/framework-exten/log/zerolog.md | 19 +- .../tutorials/framework-exten/monitor.md | 1 - .../tutorials/framework-exten/network-lib.md | 7 +- .../framework-exten/response_writer.md | 1 - .../hertz/tutorials/observability/_index.md | 1 - .../docs/hertz/tutorials/observability/log.md | 1 - .../tutorials/observability/monitoring.md | 1 - .../tutorials/service-governance/_index.md | 1 - .../service_discovery/_index.md | 28 +- .../service_discovery/consul.md | 412 +++---- .../service_discovery/etcd.md | 792 ++++++------ .../service_discovery/eureka.md | 536 ++++----- .../service_discovery/nacos.md | 807 +++++++------ .../service_discovery/polaris.md | 346 +++--- .../service_discovery/redis.md | 1062 ++++++++--------- .../service_discovery/servicecomb.md | 940 +++++++-------- .../service_discovery/zookeeper.md | 426 +++---- .../tutorials/service-migration/_index.md | 1 - .../zh/docs/hertz/tutorials/toolkit/_index.md | 1 - .../hertz/tutorials/toolkit/annotation.md | 56 +- .../docs/hertz/tutorials/toolkit/cautions.md | 67 +- .../docs/hertz/tutorials/toolkit/command.md | 17 +- .../docs/hertz/tutorials/toolkit/install.md | 14 +- .../zh/docs/hertz/tutorials/toolkit/layout.md | 6 +- .../toolkit/more-feature/api_none.md | 3 +- .../tutorials/toolkit/more-feature/client.md | 45 +- .../tutorials/toolkit/more-feature/plugin.md | 4 +- .../toolkit/more-feature/template.md | 336 +++--- .../hertz/tutorials/toolkit/usage-protobuf.md | 10 +- .../hertz/tutorials/toolkit/usage-thrift.md | 1 + .../Integration Testing/_index.md | 1 - .../Integration Testing/debug_efficiently.md | 20 +- .../Integration Testing/mock_client.md | 4 +- .../docs/kitex/Best Practice/error_handle.md | 8 +- .../kitex/Best Practice/usage_attention.md | 5 +- content/zh/docs/kitex/FAQ/_index.md | 42 +- .../zh/docs/kitex/Getting started/examples.md | 1 - .../kitex/Getting started/pre-knowledge.md | 45 +- .../kitex/Getting started/prerequisite.md | 3 +- .../docs/kitex/Getting started/quick_start.md | 10 +- .../zh/docs/kitex/Getting started/tutorial.md | 20 +- content/zh/docs/kitex/Overview/_index.md | 20 +- content/zh/docs/kitex/Reference/_index.md | 3 +- content/zh/docs/kitex/Reference/exception.md | 3 +- .../Reference/transport_protocol_ttheader.md | 6 +- content/zh/docs/kitex/Tutorials/_index.md | 4 - .../kitex/Tutorials/advanced-feature/GLS.md | 4 +- .../Tutorials/advanced-feature/_index.md | 1 - .../advanced-feature/codec_frugal.md | 39 +- .../advanced-feature/error_handler.md | 20 +- .../advanced-feature/generic-call/_index.md | 1 - .../generic-call/basic_usage.md | 15 +- .../generic-call/generic-call-dynamicgo.md | 25 +- .../thrift_idl_annotation_standards.md | 95 +- .../Tutorials/advanced-feature/metainfo.md | 23 +- .../advanced-feature/multi_service.md | 55 +- .../kitex/Tutorials/advanced-feature/xds.md | 45 +- .../kitex/Tutorials/basic-feature/_index.md | 3 +- .../basic-feature/acquire_rpcinfo.md | 20 +- .../Tutorials/basic-feature/bizstatuserr.md | 7 +- .../basic-feature/connection_type.md | 12 +- .../Tutorials/basic-feature/message_type.md | 40 +- .../basic-feature/protocol/_index.md | 1 - .../protocol/serialization-protocol/_index.md | 2 +- .../protocol/serialization-protocol/binary.md | 2 +- .../serialization-protocol/hessian2.md | 3 +- .../serialization-protocol/protobuf.md | 2 +- .../protocol/transport-streaming/_index.md | 1 - .../transport-streaming/thrift_streaming.md | 124 +- .../Tutorials/basic-feature/visit_directly.md | 8 - .../Tutorials/basic-feature/warming_up.md | 1 - .../docs/kitex/Tutorials/code-gen/_index.md | 1 - .../Tutorials/code-gen/code_generation.md | 41 +- .../kitex/Tutorials/code-gen/custom_tpl.md | 8 +- .../kitex/Tutorials/code-gen/idl_trimmer.md | 93 +- .../Tutorials/code-gen/template_extension.md | 30 +- .../kitex/Tutorials/code-gen/validator.md | 20 +- .../kitex/Tutorials/framework-exten/_index.md | 1 - .../Tutorials/framework-exten/middleware.md | 32 +- .../Tutorials/framework-exten/registry.md | 8 +- .../kitex/Tutorials/framework-exten/suite.md | 1 + .../framework-exten/trans_pipeline.md | 5 +- .../Tutorials/framework-exten/transmeta.md | 2 +- .../Tutorials/framework-exten/transport.md | 4 +- .../kitex/Tutorials/observability/_index.md | 1 - .../observability/instrumentation.md | 6 +- .../Tutorials/observability/monitoring.md | 56 +- .../zh/docs/kitex/Tutorials/options/_index.md | 1 - .../kitex/Tutorials/options/call_options.md | 12 - .../kitex/Tutorials/options/client_options.md | 112 +- .../kitex/Tutorials/options/server_options.md | 82 +- .../Tutorials/service-governance/_index.md | 3 +- .../service-governance/circuitbreaker.md | 17 +- .../config-center/_index.md | 7 +- .../config-center/apollo.md | 140 ++- .../config-center/consul.md | 25 +- .../service-governance/config-center/etcd.md | 137 ++- .../service-governance/config-center/file.md | 237 ++-- .../service-governance/config-center/nacos.md | 143 +-- .../config-center/zookeeper.md | 93 +- .../Tutorials/service-governance/fallback.md | 17 +- .../Tutorials/service-governance/limiting.md | 1 + .../service-governance/loadbalance.md | 11 +- .../Tutorials/service-governance/retry.md | 44 +- .../service_discovery/_index.md | 13 +- .../service_discovery/consul.md | 5 +- .../service_discovery/etcd.md | 13 +- .../service_discovery/eureka.md | 5 +- .../service_discovery/nacos.md | 31 +- .../service_discovery/polaris.md | 4 +- .../service_discovery/rule-based.md | 63 +- .../service_discovery/service-comb.md | 1 - .../service_discovery/zookeeper.md | 1 - .../Tutorials/service-governance/timeout.md | 40 +- content/zh/docs/kitex/_index.md | 6 +- .../zh/docs/netpoll/Common Usage/_index.md | 13 +- .../zh/docs/netpoll/Getting started/_index.md | 14 +- content/zh/docs/netpoll/Overview/_index.md | 40 +- content/zh/docs/netpoll/_index.md | 6 +- content/zh/docs/volo/_index.md | 6 +- content/zh/docs/volo/faq/_index.md | 2 +- content/zh/docs/volo/guide/config.md | 33 +- content/zh/docs/volo/guide/discovery_lb.md | 2 +- content/zh/docs/volo/guide/metadata.md | 1 - content/zh/docs/volo/guide/observability.md | 1 - content/zh/docs/volo/guide/with_callopt.md | 1 - content/zh/docs/volo/motore/_index.md | 6 +- content/zh/docs/volo/overview/_index.md | 2 +- content/zh/docs/volo/pilota/_index.md | 7 +- content/zh/docs/volo/volo-grpc/_index.md | 2 - content/zh/docs/volo/volo-thrift/_index.md | 1 - content/zh/search.md | 2 - content/zh/security/_index.md | 2 - .../security/safety-bulletin/detail/_index.md | 1 - .../detail/cloudwego-sa-2022-1/index.md | 6 + .../detail/cloudwego-sa-2022-2/index.md | 7 + 585 files changed, 12729 insertions(+), 12048 deletions(-) diff --git a/content/en/blog/_index.md b/content/en/blog/_index.md index 43bd7ecfd7..d203ecb92b 100644 --- a/content/en/blog/_index.md +++ b/content/en/blog/_index.md @@ -7,8 +7,6 @@ menu: weight: 20 --- - This is the **blog** section. It has two categories: News and Releases. Files in these directories will be listed in reverse chronological order. - diff --git a/content/en/blog/news/1st_RPCKitex/index.md b/content/en/blog/news/1st_RPCKitex/index.md index 489b781819..a34e9079f1 100644 --- a/content/en/blog/news/1st_RPCKitex/index.md +++ b/content/en/blog/news/1st_RPCKitex/index.md @@ -3,7 +3,15 @@ date: 2022-09-30 title: "Kitex: Unifying Open Source Practice for a High-Performance RPC Framework" projects: ["Kitex"] linkTitle: "Kitex: Unifying Open Source Practice for a High-Performance RPC Framework" -keywords: ["CloudWeGo", "RPC framework", "Kitex", "microservice framework", "ByteDance Open Source", "open source"] +keywords: + [ + "CloudWeGo", + "RPC framework", + "Kitex", + "microservice framework", + "ByteDance Open Source", + "open source", + ] description: "This article provides an overview of CloudWeGo - Kitex, a high-performance RPC framework, including its origins, development history, and the progress made since its open-source release a year ago. It covers the evolution of functional features, contributions from the community to the ecosystem, and successful implementation practices by enterprises. It highlights the growth and improvements Kitex has undergone, showcasing its commitment to delivering a robust and efficient solution for RPC communication in various scenarios." author: CloudWeGo Team --- diff --git a/content/en/blog/news/Delving_Deeper_Enriching_Microservices_with_Golang_and_Rust_with_CloudWeGo/index.md b/content/en/blog/news/Delving_Deeper_Enriching_Microservices_with_Golang_and_Rust_with_CloudWeGo/index.md index 6e9fef3756..eb31c9a468 100644 --- a/content/en/blog/news/Delving_Deeper_Enriching_Microservices_with_Golang_and_Rust_with_CloudWeGo/index.md +++ b/content/en/blog/news/Delving_Deeper_Enriching_Microservices_with_Golang_and_Rust_with_CloudWeGo/index.md @@ -3,9 +3,28 @@ date: 2024-02-21 title: "Delving Deeper: Enriching Microservices with Golang with CloudWeGo" projects: ["CloudWeGo"] linkTitle: "Delving Deeper: Enriching Microservices with Golang with CloudWeGo" -keywords: ["CloudWeGo", "middleware", "Kitex", "Netpoll", "Golang", "Volo", "rust", "microservice framework", "ByteDance Open Source", "ByteDance", "open source", "cloud native", "open source", "gRPC", "microservices", "rpc", "thrift"] +keywords: + [ + "CloudWeGo", + "middleware", + "Kitex", + "Netpoll", + "Golang", + "Volo", + "rust", + "microservice framework", + "ByteDance Open Source", + "ByteDance", + "open source", + "cloud native", + "open source", + "gRPC", + "microservices", + "rpc", + "thrift", + ] description: "Delve into CloudWeGo's Kitex through practical examples, where high performance and extensibility redefine microservice excellence." -author: Yacine Si Tayeb +author: Yacine Si Tayeb --- What if there existed an RPC framework that provided not only high performance and extensibility but also a robust suite of features and a thriving community support? @@ -28,7 +47,7 @@ Consider the case of Bookinfo, a sample application provided by [Istio](https:// This use case is illustrative of how traffic-heavy services can significantly benefit from CloudWeGo's performance promise. This integration also demonstrates how CloudWeGo stands above traditional Istio service mesh when it comes to traffic handling and performance. -![Image](/img/blog/Delving_Deeper_Enriching_Microservices_with_Golang_and_Rust_with_CloudWeGo/2.jpeg) +![Image](/img/blog/Delving_Deeper_Enriching_Microservices_with_Golang_and_Rust_with_CloudWeGo/2.jpeg) With Kitex and [Hertz](/docs/hertz/) handling traffic redirection, the Bookinfo project can manage high traffic volumes efficiently, ensuring swift responses and a better user experience. @@ -50,7 +69,7 @@ The above code snippet is a simplified example of how the Bookinfo project can b CloudWeGo's commitment to simplifying complex tasks shines in its application to the Easy Note project. It leverages CloudWeGo to implement a full-process traffic lane. The note-taking platform needs to be responsive and efficient, a need fulfilled by CloudWeGo's high-performance networking library, [Netpoll](/docs/netpoll/). -![Image](/img/blog/Delving_Deeper_Enriching_Microservices_with_Golang_and_Rust_with_CloudWeGo/3.jpeg) +![Image](/img/blog/Delving_Deeper_Enriching_Microservices_with_Golang_and_Rust_with_CloudWeGo/3.jpeg) The integration of CloudWeGo has elevated the Easy Note application to compete effectively with other note-taking platforms, proving how simplicity can indeed lead to power. @@ -80,7 +99,7 @@ The snippet above gives a glimpse of how CloudWeGo helps to enhance the efficien In the bustling e-commerce landscape, Book Shop stands as a testament to CloudWeGo's capacity for seamless integration. Integrating middleware like [Elasticsearch](https://www.elastic.co/elasticsearch) and [Redis](https://redis.io) into a Kitex project to build a solid e-commerce system that rivals more complex platforms. -![Image](/img/blog/Delving_Deeper_Enriching_Microservices_with_Golang_and_Rust_with_CloudWeGo/4.jpeg) +![Image](/img/blog/Delving_Deeper_Enriching_Microservices_with_Golang_and_Rust_with_CloudWeGo/4.jpeg) CloudWeGo's ability to effectively integrate with popular technologies like Elasticsearch and Redis ensures that businesses need not compromise on choosing an open-source RPC framework. @@ -112,7 +131,7 @@ The above snippet is a basic representation of how the Book Shop e-commerce syst The FreeCar project is an excellent illustration of how CloudWeGo can revamp the operations in a time-sharing car rental system, posing a strong alternative to existing ride-hailing applications. -![Image](/img/blog/Delving_Deeper_Enriching_Microservices_with_Golang_and_Rust_with_CloudWeGo/5.jpeg) +![Image](/img/blog/Delving_Deeper_Enriching_Microservices_with_Golang_and_Rust_with_CloudWeGo/5.jpeg) This real-world implementation demonstrates how CloudWeGo's robust features can optimize operations, fostering efficiency and scalability in industries beyond tech. @@ -151,6 +170,6 @@ As I venture further into the landscape of alternative RPC frameworks, and explo # Embracing the Future of Microservices -With each use case, CloudWeGo's potential becomes increasingly clear. Developers can now build high-performing, extensible, and robust applications, harnessing the true essence of microservices - no matter if they prefer working with Golang or Rust. +With each use case, CloudWeGo's potential becomes increasingly clear. Developers can now build high-performing, extensible, and robust applications, harnessing the true essence of microservices - no matter if they prefer working with Golang or Rust. If you're considering a new tool for your microservice architecture, especially if you are interested in Rust, [give CloudWeGo a try](/docs/). The future of microservices awaits you. diff --git a/content/en/blog/news/Enhancing_Performance_in_Microservice_Architecture_with_Kitex/Enhancing_Performance_in_Microservice_Architecture_with_Kitex.md b/content/en/blog/news/Enhancing_Performance_in_Microservice_Architecture_with_Kitex/Enhancing_Performance_in_Microservice_Architecture_with_Kitex.md index 08b549d47d..a4615fbb26 100644 --- a/content/en/blog/news/Enhancing_Performance_in_Microservice_Architecture_with_Kitex/Enhancing_Performance_in_Microservice_Architecture_with_Kitex.md +++ b/content/en/blog/news/Enhancing_Performance_in_Microservice_Architecture_with_Kitex/Enhancing_Performance_in_Microservice_Architecture_with_Kitex.md @@ -3,24 +3,44 @@ date: 2024-01-29 title: "Enhancing Performance in Microservice Architecture with Kitex" projects: ["CloudWeGo"] linkTitle: "Enhancing Performance in Microservice Architecture with Kitex" -keywords: ["CloudWeGo", "middleware", "Go", "Golang", "Kitex", "microservice framework", "ByteDance Open Source", "ByteDance", "open source", "cloud native", "open source", "kubernetes", "gRPC", "microservices", "rpc", "thrift"] +keywords: + [ + "CloudWeGo", + "middleware", + "Go", + "Golang", + "Kitex", + "microservice framework", + "ByteDance Open Source", + "ByteDance", + "open source", + "cloud native", + "open source", + "kubernetes", + "gRPC", + "microservices", + "rpc", + "thrift", + ] description: "This post explores the creation and optimization of ByteDance's Remote Procedure Call (RPC) framework, Kitex, to address challenges within microservice architecture. Highlighting innovative performance optimization techniques, controlled Garbage Collection and concurrency adjustment, this insightful read offers hands-on strategies and future plans for evolving high-performance microservice systems." -author: Zhuowei Wang, Felix Feng, Yacine Si Tayeb +author: Zhuowei Wang, Felix Feng, Yacine Si Tayeb --- ![Image](/img/blog/Enhancing_Performance_in_Microservice_Architecture_with_Kitex/1.jpeg) # Kitex: Enhancing Performance in Microservice Architecture + ## Introduction -The team at ByteDance initiated the creation of the Remote Procedure Call (RPC) framework, Kitex, alongside several related fundamental libraries in 2019. This endeavor originated from confronting functionality and performance challenges within our extensive microservice architecture. We also wanted to combine the knowledge and insights gathered from previous frameworks. This development project was officially released for open-source contribution on GitHub in 2021. +The team at ByteDance initiated the creation of the Remote Procedure Call (RPC) framework, Kitex, alongside several related fundamental libraries in 2019. This endeavor originated from confronting functionality and performance challenges within our extensive microservice architecture. We also wanted to combine the knowledge and insights gathered from previous frameworks. This development project was officially released for open-source contribution on GitHub in 2021. -From 2019 to 2023, our internal microservices have seen substantial growth. During this period, [the Kitex framework](/docs/kitex/overview/) has undergone numerous cycles of optimization and testing to enhance its performance and efficiency. In this article, we share performance optimization techniques that we've systematically implemented over the past few years. +From 2019 to 2023, our internal microservices have seen substantial growth. During this period, [the Kitex framework](/docs/kitex/overview/) has undergone numerous cycles of optimization and testing to enhance its performance and efficiency. In this article, we share performance optimization techniques that we've systematically implemented over the past few years. ## The Evolution and Status Quo of Kitex + ### Understanding the Need for an RPC Framework -Although the Remote Procedure Call (RPC) framework has a long history, its wide-scale use as a crucial component aligns with the advent of microservice architecture. Therefore, it's vital to revisit its historical developments and comprehend why an RPC framework is necessary. +Although the Remote Procedure Call (RPC) framework has a long history, its wide-scale use as a crucial component aligns with the advent of microservice architecture. Therefore, it's vital to revisit its historical developments and comprehend why an RPC framework is necessary. #### Background: Monolithic Architecture Era @@ -46,13 +66,13 @@ func GetItem(itemId) { return db.items.GetItem(itemId) } ``` + ![Image](/img/blog/Enhancing_Performance_in_Microservice_Architecture_with_Kitex/2.jpeg) -This style of coding is straightforward, especially once built on top of a well-structured design pattern, can make it straightforward to refactor and write unit tests. Many IT systems still operate using this architecture. +This style of coding is straightforward, especially once built on top of a well-structured design pattern, can make it straightforward to refactor and write unit tests. Many IT systems still operate using this architecture. However, as online businesses rapidly developed, we encountered the following limitations in some of the larger internet projects: - 1. There's a limit to computational power: the maximum computing power of a single request is less than or equal to the total computational power of a single server divided by the number of requests processed simultaneously. 2. There's a constraint around developmental efficiency: the growth of the code repository, team size, and code complexity do not have a linear relationship. This makes maintenance incrementally more challenging as the business grows, resulting in a more complicated online implementations. @@ -76,7 +96,6 @@ RPCs (Remote Procedure Call) allows business systems to call remote services as Before the introduction of RPC, the sole overhead in the following code is merely a function call, an operation at the nanosecond level, not accounting for inline optimization. - ```Go func client() (response) { response = server(request) // function call @@ -87,7 +106,7 @@ func server(request) (response) { } ``` -Upon transitioning to an RPC call, the overhead directly elevates to the millisecond level, a latency difference of 10^6, which highlights the high cost of RPC and indicates considerable room for optimization. +Upon transitioning to an RPC call, the overhead directly elevates to the millisecond level, a latency difference of 10^6, which highlights the high cost of RPC and indicates considerable room for optimization. ``` func client() (response) { @@ -97,7 +116,8 @@ func client() (response) { func server(request) (response) { response.Message = request.Message } -``` +``` + The complete process of an RPC call is outlined below, and we will elaborate on our performance optimization practices for each step in the sections to follow. ![Image](/img/blog/Enhancing_Performance_in_Microservice_Architecture_with_Kitex/4.jpeg) @@ -148,7 +168,7 @@ Memory reuse is a significant challenge, which often leads to the overhead of ga ### Code Generation Optimization: Introducing FastThrift & FastPB -We've introduced encoding and decoding capabilities to Kitex by generating a large volume of code for both Thrift and Protobuf protocols. Since generated code can optimize preset runtime information, we can avoid additional operations during runtime and achieve several benefits. +We've introduced encoding and decoding capabilities to Kitex by generating a large volume of code for both Thrift and Protobuf protocols. Since generated code can optimize preset runtime information, we can avoid additional operations during runtime and achieve several benefits. **Memory Reuse and Size Pre-calculation** @@ -161,13 +181,13 @@ type User struct { Id int32 Name string } - + func (x *User) Size() (n int) { n += x.sizeField1() n += x.sizeField2() return n } - + // Framework Process size := msg.Size() data = Malloc(size) // allocate memory @@ -220,18 +240,19 @@ The feedback encouraged us to consider if the previously generated code could be ![Image](/img/blog/Enhancing_Performance_in_Microservice_Architecture_with_Kitex/10.jpeg) -### Advantages of JIT +### Advantages of JIT 1. Registers utilization and deeper inlining: this improves the efficiency of function calls. 2. Core computational functions use fully optimized assembly code, which leads to improved performance. ### Optimization Results of JIT + As a result of JIT optimization, we improved the optimization result from 3.58% to an impressive 0.78%. ![Image](/img/blog/Enhancing_Performance_in_Microservice_Architecture_with_Kitex/11.jpeg) -### Comparing Frugal and Apache Thrift +### Comparing Frugal and Apache Thrift This section presents a performance comparison of Frugal and Apache Thrift in the context of encoding and decoding. @@ -242,6 +263,7 @@ This section presents a performance comparison of Frugal and Apache Thrift in th ![Image](/img/blog/Enhancing_Performance_in_Microservice_Architecture_with_Kitex/13.jpeg) ### Native Go Net Challenges in RPC Scenarios + Native Go Net in RPC situations presents the following challenges: 1. Each connection corresponds to one coroutine - when there are numerous upstream and downstream instances, the sheer number of Goroutines can significantly influence performance. This is particularly detrimental for businesses with intensive instances. @@ -250,7 +272,7 @@ Native Go Net in RPC situations presents the following challenges: 3. When a struct undergoes NoCopy serialization, the output typically takes the form of a two-dimensional byte array. However, Go's `Write([]byte)` interface falls short as it does not support handling non-continuous memory data. -4. Despite being highly compatible, it's provided by Go Runtime and not conducive or suitable for adding new features. +4. Despite being highly compatible, it's provided by Go Runtime and not conducive or suitable for adding new features. ![Image](/img/blog/Enhancing_Performance_in_Microservice_Architecture_with_Kitex/14.jpeg) @@ -295,7 +317,7 @@ Here are the main areas we focused on for optimization: ![Image](/img/blog/Enhancing_Performance_in_Microservice_Architecture_with_Kitex/17.jpeg) -After introducing Service Mesh, the business process primarily communicates with another sidecar process on the same machine, which brings in an additional layer of delay. +After introducing Service Mesh, the business process primarily communicates with another sidecar process on the same machine, which brings in an additional layer of delay. Traditional Service Mesh solutions commonly hijack iptables to facilitate traffic forwarding to the sidecar process. This could lead to substantial performance loss at all levels. Kitex has carried out several performance optimization attempts at the communication layer and has finally developed a systematic solution. @@ -334,7 +356,7 @@ Our performance test indicates the following: ![Image](/img/blog/Enhancing_Performance_in_Microservice_Architecture_with_Kitex/19.jpeg) -In pursuit of enhancing the efficiency of inter-process communication, we developed a communication mode based on shared memory. Shared memory communication throws in the complexity of managing the synchronization of various communication states across different processes. +In pursuit of enhancing the efficiency of inter-process communication, we developed a communication mode based on shared memory. Shared memory communication throws in the complexity of managing the synchronization of various communication states across different processes. To tackle this, we utilized our communication protocol and retained **UDS** as the event notification channel (IO Queue) and shared memory as the data transmission channel (Buffer). @@ -348,7 +370,7 @@ For a detailed technical understanding of shmipc, you can refer to our previousl # From Cross-Machine to Intra-Machine Communication: A Pod Affinity Solution -Having previously optimized intra-machine communication, we found that it's limited to the data plane communication between the service process and the Service Mesh. +Having previously optimized intra-machine communication, we found that it's limited to the data plane communication between the service process and the Service Mesh. The peer service is possibly not hosted on the same machine. So, the question arises, how can we optimize cross-machine communication? One innovative approach we're considering is converting cross-machine issues into intra-machine issues. @@ -366,7 +388,7 @@ Achieving this in large-scale microservice communication calls for the cooperati # Microservice Online Tuning Practices -Apart from performance optimization at the framework level, the business logic itself is a significant contributor to the performance bottleneck. To combat this, we have accumulated several practical experiences and strategies. +Apart from performance optimization at the framework level, the business logic itself is a significant contributor to the performance bottleneck. To combat this, we have accumulated several practical experiences and strategies. ![Image](/img/blog/Enhancing_Performance_in_Microservice_Architecture_with_Kitex/24.jpeg) @@ -426,9 +448,9 @@ apiVersion: v1 kind: Pod spec: containers: - - resources: - limits: - cpu: "4" + - resources: + limits: + cpu: "4" ``` The rapid advancement of container technology has largely affected the development of microservices. Currently, the majority of microservices, including numerous databases across the industry, operate within container environments. For the purpose of this discussion, we'll only touch upon mainstream containers based on cgroup technology. @@ -451,6 +473,7 @@ processor : 2 processor : 3 // ... ``` + However, these are merely illusions concocted by the container to ease your mental load off programming. The underlying reason for creating such an illusion is to ensure traditional Linux Debug tools function seamlessly within the container environment. Contrarily, container technology based on cgroups imposes limits only on **CPU time**, not on the number of CPUs. Suppose you log into the machine to verify the CPU number each thread of the process is using. In that case, you might be taken aback to discover that the sum exceeds the CPU limit set for the container: @@ -463,13 +486,13 @@ When a container requests 4 CPU units, it means it can run for an equivalent of Knowing the upper bound for physical parallel computing in a program is considerably high, we can leverage this insight to increase or decrease the number of working threads (GOMAXPROCS) or adjust the degree of concurrency within the program. -Let's consider a calling scenario where the business sends requests to the same upstream with four concurrent processes. Each request upstream requires 50ms of processing time. Based on this, the downstream sets the timeout time to **100ms**. +Let's consider a calling scenario where the business sends requests to the same upstream with four concurrent processes. Each request upstream requires 50ms of processing time. Based on this, the downstream sets the timeout time to **100ms**. Though this seems reasonable, if, at that time, the upstream had only two CPUs available to handle requests (which also have to manage other work or perform Garbage Collection activities), the third RPC request would likely time out. ![Image](/img/blog/Enhancing_Performance_in_Microservice_Architecture_with_Kitex/29.jpeg) -However, simply reducing concurrency isn't always the solution and it doesn't benefit all cases. +However, simply reducing concurrency isn't always the solution and it doesn't benefit all cases. ![Image](/img/blog/Enhancing_Performance_in_Microservice_Architecture_with_Kitex/30.jpeg) @@ -477,17 +500,17 @@ If upstream's computational resources are abundantly available, increasing concu ## Balancing Resource Utilization – Reserving Computational Capacity for Other Processes -If there are multiple processes within the container, it's essential to reserve resources for these operations. This consideration is particularly crucial in scenarios like the deployment of a Service Mesh data plane, where the same container operates as a sidecar. +If there are multiple processes within the container, it's essential to reserve resources for these operations. This consideration is particularly crucial in scenarios like the deployment of a Service Mesh data plane, where the same container operates as a sidecar. If a downstream process utilizes the entirety of the time slice allocated within a computation cycle, it's highly probable that it'll face resource throttling when it's the upstream process's turn, which could subsequently affect the service’s latency. ## Optimizing Service Concurrency Degree -* **Adjust the Number of Work Threads**: For instance, the `GOMAXPROCS` directive in Go allows us to modify the number of working threads. +- **Adjust the Number of Work Threads**: For instance, the `GOMAXPROCS` directive in Go allows us to modify the number of working threads. -* **Alter the Concurrency of Requests in the Code**: It's essential for businesses to iteratively test and evaluate the trade-off between the latency gains from increasing concurrency and the stability loss at peak levels to determine an optimal concurrency value. +- **Alter the Concurrency of Requests in the Code**: It's essential for businesses to iteratively test and evaluate the trade-off between the latency gains from increasing concurrency and the stability loss at peak levels to determine an optimal concurrency value. -* **Use Batch Interfaces**: If the business scenario allows, replacing the current interface with a batch interface could be a more effective strategy. +- **Use Batch Interfaces**: If the business scenario allows, replacing the current interface with a batch interface could be a more effective strategy. # Looking into the Future of Optimization @@ -497,21 +520,21 @@ Currently the only area we haven't explored for optimization is the Kernel. ![Image](/img/blog/Enhancing_Performance_in_Microservice_Architecture_with_Kitex/31.jpeg) -In online business environments, we often observe that the communication overhead of RPC accounts for more than 20% of the total overhead for services heavy on I/O operations, even after optimizing RPC to the level of intra-machine communication. +In online business environments, we often observe that the communication overhead of RPC accounts for more than 20% of the total overhead for services heavy on I/O operations, even after optimizing RPC to the level of intra-machine communication. At this point, we've optimized inter-process communication to its extremes. If we are to seek further improvements, we need to break through the existing constraints in Linux inter-process communication fundamentally. We've already made some preliminary strides in this area. We will continue to share updates on this topic in future articles, so stay tuned. -## Reassessing the TCP Protocol +## Reassessing the TCP Protocol In the context of internal data center communication, the TCP protocol displays some limitations: -* Given the superior internal network quality and an incredibly low packet loss rate, many designs within TCP appear redundant. +- Given the superior internal network quality and an incredibly low packet loss rate, many designs within TCP appear redundant. -* In situations of large-scale point-to-point communication, TCP long connections may inadvertently degrade into short connections. +- In situations of large-scale point-to-point communication, TCP long connections may inadvertently degrade into short connections. -* While the application layer uses "messages" as a unit, TCP data streams don't offer clear message boundaries, which could complicate synchronization and message handling. +- While the application layer uses "messages" as a unit, TCP data streams don't offer clear message boundaries, which could complicate synchronization and message handling. This has led us to question whether we need to develop a proprietary data center protocol, better suited to handle RPC communication. @@ -521,26 +544,25 @@ When it comes to existing components, we plan to continue our efforts to enhance **Frugal, the Thrift JIT Encoder/Decoder:** -* Introducing support for the ARM architecture. +- Introducing support for the ARM architecture. -* Optimizing the backend with Static Single Assignment (SSA). - -* Accelerating performance with Single Instruction, Multiple Data (SIMD) operations. +- Optimizing the backend with Static Single Assignment (SSA). +- Accelerating performance with Single Instruction, Multiple Data (SIMD) operations. **Netpoll Network Library:** -* Refactoring interfaces to ensure seamless integration with existing libraries in the Go ecosystem. +- Refactoring interfaces to ensure seamless integration with existing libraries in the Go ecosystem. -* Implementing support for Shared Memory Communications over RDMA (SMC-R). +- Implementing support for Shared Memory Communications over RDMA (SMC-R). **Pod Affinity:** -* Expanding from same-machine to same-rack granularity, effectively reducing network latency and improving performance. +- Expanding from same-machine to same-rack granularity, effectively reducing network latency and improving performance. -In this post, we explored optimizing microservices performance using Kitex, the RPC framework developed by ByteDance. We discussed various techniques, from encoding and decoding enhancements, JIT compilation, network library optimization, and communication layer upgrades, to automated GC optimization, concurrent processing strategies, and microservices online tuning practices. +In this post, we explored optimizing microservices performance using Kitex, the RPC framework developed by ByteDance. We discussed various techniques, from encoding and decoding enhancements, JIT compilation, network library optimization, and communication layer upgrades, to automated GC optimization, concurrent processing strategies, and microservices online tuning practices. -Kitex has demonstrated its ability to outperform other frameworks in testing comparisons, showcasing its strength in handling complex microservice architectures. +Kitex has demonstrated its ability to outperform other frameworks in testing comparisons, showcasing its strength in handling complex microservice architectures. -We also briefly looked towards future optimizations, including kernel-level improvements, restructuring the TCP protocols, and further refinement of existing components. With continuous learning and improvements, we are driven to unlock the vast potential in microservice performance optimization, taking us one step closer to the realm of real-time computing. +We also briefly looked towards future optimizations, including kernel-level improvements, restructuring the TCP protocols, and further refinement of existing components. With continuous learning and improvements, we are driven to unlock the vast potential in microservice performance optimization, taking us one step closer to the realm of real-time computing. For any questions or discussions, you're welcome to join our community on [GitHub](https://github.com/cloudwego) or [Discord](https://discord.gg/jceZSE7DsW). diff --git a/content/en/blog/news/Harnessing_the_Power_of_Rust_for_Cloud_Development_with_Volo/index.md b/content/en/blog/news/Harnessing_the_Power_of_Rust_for_Cloud_Development_with_Volo/index.md index 210e5f17a5..651b759a03 100644 --- a/content/en/blog/news/Harnessing_the_Power_of_Rust_for_Cloud_Development_with_Volo/index.md +++ b/content/en/blog/news/Harnessing_the_Power_of_Rust_for_Cloud_Development_with_Volo/index.md @@ -3,16 +3,33 @@ date: 2024-01-18 title: "Harnessing the Power of Rust for Cloud Development with Volo" projects: ["CloudWeGo"] linkTitle: "Harnessing the Power of Rust for Cloud Development with Volo" -keywords: ["CloudWeGo", "middleware", "Volo", "rust", "microservice framework", "ByteDance Open Source", "ByteDance", "open source", "cloud native", "open source", "kubernetes", "gRPC", "microservices", "rpc", "thrift"] +keywords: + [ + "CloudWeGo", + "middleware", + "Volo", + "rust", + "microservice framework", + "ByteDance Open Source", + "ByteDance", + "open source", + "cloud native", + "open source", + "kubernetes", + "gRPC", + "microservices", + "rpc", + "thrift", + ] description: "Volo is a Rust framework for cloud development. This guide provides insights into leveraging Volo with its speed and efficiency in your projects." -author: Yacine Si Tayeb, Guangming Luo +author: Yacine Si Tayeb, Guangming Luo --- -![Image](/img/blog/Harnessing_the_Power_of_Rust_for_Cloud_Development_with_Volo/1.jpeg) +![Image](/img/blog/Harnessing_the_Power_of_Rust_for_Cloud_Development_with_Volo/1.jpeg) ## I. Introduction -Every tool in the [CloudWeGo](https://www.cloudwego.io) open-source ecosystem has been developed with the aim of simplifying and revolutionizing how developers navigate the cloud environment. An essential part of this ecosystem is [Volo](/docs/volo/), a Rust RPC framework designed to provide a seamless and efficient communication infrastructure. +Every tool in the [CloudWeGo](https://www.cloudwego.io) open-source ecosystem has been developed with the aim of simplifying and revolutionizing how developers navigate the cloud environment. An essential part of this ecosystem is [Volo](/docs/volo/), a Rust RPC framework designed to provide a seamless and efficient communication infrastructure. This guide aims to provide in-depth insights into leveraging Volo in your projects. Built with [Rust](https://www.rust-lang.org), Volo brings unique features and advantages into the mix. @@ -20,7 +37,7 @@ This guide aims to provide in-depth insights into leveraging Volo in your projec As a part of the CloudWeGo family, Volo can make a significant impact in real-world applications. Its high-speed processing capabilities, when combined with the safety and concurrency advantages of Rust, can provide an efficient backbone to high-performance web services and applications. -The beauty of Rust, which Volo encapsulates, is its ability to push beyond the performance boundaries typically associated with languages such as Go. While Go is highly efficient, it does reach a performance ceiling that may not lend itself to deep optimization. However, once a finely optimized Go service is rewritten in Rust, the benefits spring into view. +The beauty of Rust, which Volo encapsulates, is its ability to push beyond the performance boundaries typically associated with languages such as Go. While Go is highly efficient, it does reach a performance ceiling that may not lend itself to deep optimization. However, once a finely optimized Go service is rewritten in Rust, the benefits spring into view. Here, CPU gains generally rise above 30%, some even reaching over 50%. In some cases, a fourfold increase in CPU gains is observed. Memory gains are even more pronounced, regularly topping 50% and in some cases reaching as high as 90%. @@ -30,7 +47,7 @@ Consider the infrastructure of an online marketplace's back-end. Volo can facili Another use case could be in the gaming industry, where Volo can help manage player data, game state, and real-time multiplayer interactions with low-latency and high reliability. -Rust and Go are not adversaries but rather allies that complement each other, leveraging their respective strengths to compensate for any weaknesses. For applications where ultimate performance, low latency, memory bottlenecks, and stability are of paramount importance, even if it comes at the cost of some iteration speed loss, Rust is the go-to choice. +Rust and Go are not adversaries but rather allies that complement each other, leveraging their respective strengths to compensate for any weaknesses. For applications where ultimate performance, low latency, memory bottlenecks, and stability are of paramount importance, even if it comes at the cost of some iteration speed loss, Rust is the go-to choice. These applications can fully benefit from Rust's, and by extension Volo's, unrivaled performance optimization and security. However, when performance sensitivity takes a backseat to high I/O operations, and when rapid development and iteration receives priority over stability, Go becomes the preferred choice. @@ -41,10 +58,13 @@ Rust's vast applicability doesn't stop at server-side business and architectural CloudWeGo provides a robust set of tools to work with, one of which is Volo. Here's how you can kickstart your journey with Volo within the CloudWeGo ecosystem. ### Volo + #### Prerequisites + If you don’t have the Rust development environment set up, please follow [Install Rust](https://www.rust-lang.org/tools/install) to download Rustup and install Rust. Volo supports Linux, macOS, and Windows systems by default. #### Install the CLI tool + Volo provides CLI tools of the same name for initializing projects, managing IDLs, and more. To install Volo tool, run the following command: `cargo install volo-cli`. Then run: `volo help` @@ -63,7 +83,6 @@ SUBCOMMANDS: help Print this message or the help of the given subcommand(s) idl manage your idl ``` - ## IV. Creating A Sample Project With CloudWeGo When starting a new project with Volo, the following steps can guide you through the development of basic components. @@ -106,6 +125,7 @@ service ItemService { Init the server project volo init volo-example idl/volo_example.thrift ``` + **Note:** Here we use the `init` command, followed by the name of our project, which means we need to generate template code. At the end, you need to specify an IDL used by the server. At this point, our entire directory structure looks like this: @@ -126,6 +146,7 @@ At this point, our entire directory structure looks like this: │ └── lib.rs └── volo.yml ``` + **2. Add logic code** Open `src/lib.rs` and add the method implementation to the impl block: @@ -149,11 +170,13 @@ impl volo_gen::volo::example::ItemService for S { ``` cargo update && cargo build ``` + At this point, you will find `volo_gen.rs` file under `OUT_DIR Directory`. Then execute the following command to get our server running: ``` cargo run --bin server ``` + We now have our server running! ### gRPC project @@ -166,6 +189,7 @@ To create a gRPC project, we need to write a protobuf IDL first. In your working mkdir volo-example && cd volo-example mkdir idl && vim idl/volo_example.proto ``` + Then, enter the following content: ``` @@ -192,11 +216,13 @@ service ItemService { rpc GetItem(GetItemRequest) returns (GetItemResponse); } ``` + **2. Init the server project** ``` volo init --includes=idl volo-example idl/volo_example.proto ``` + **Note:** Here we use the `init` command, followed by the name of our project, which means we need to generate template code. At the end, you need to specify an IDL used by the server. At this point, our entire directory structure looks like this: @@ -247,8 +273,8 @@ At this point, you will find `volo_gen.rs` file under `OUT_DIR Directory`. Then ``` cargo run --bin server ``` -If you followed the above steps, you'll now have your server running! +If you followed the above steps, you'll now have your server running! ## V. Troubleshooting Tips & FAQ diff --git a/content/en/blog/news/Hertz_Benchmark/index.md b/content/en/blog/news/Hertz_Benchmark/index.md index 456f03187a..4e26f7e1d2 100644 --- a/content/en/blog/news/Hertz_Benchmark/index.md +++ b/content/en/blog/news/Hertz_Benchmark/index.md @@ -10,6 +10,7 @@ author: Duslia --- ## Background + On September 8, 2021, ByteDance officially announced the open-sourcing of [CloudWeGo][CloudWeGo]. CloudWeGo is a set of microservices middleware developed by ByteDance, characterized by high performance, strong scalability, and high stability. It focuses on solving the difficulties of microservices communication and governance, and meets the demands of different businesses in different scenarios. @@ -24,7 +25,7 @@ Users can also refer to the official load testing project [hertz-benchmark][hert [Hertz][Hertz] was born out of large-scale microservices practice at ByteDance, and is naturally designed for microservices scenarios. Therefore, in the following, we will first introduce the characteristics of the HTTP microservices to facilitate developers' deeper understanding of [Hertz][Hertz]'s design considerations. -* **HTTP Communication Model** +- **HTTP Communication Model** Communication between microservices typically follows a Ping-Pong model. In addition to conventional throughput performance metrics, developers also need to consider the average latency of each HTTP request. While increasing the number of machines can quickly resolve throughput bottlenecks, reducing latency, which significantly affects user experience, is not as easy. @@ -32,7 +33,7 @@ While increasing the number of machines can quickly resolve throughput bottlenec In the environment of microservices, a single call often requires collaboration from multiple microservices. Even if each node has low latency, the final latency on the entire chain can be amplified. Therefore, latency is a more critical metric for developers to pay attention to in microservices. [Hertz][Hertz] has made certain optimizations for latency while ensuring throughput. -* **The Use of Long and Short Connections** +- **The Use of Long and Short Connections** Since establishing a TCP connection requires a three-way handshake, the overhead of creating a new connection for each request can be very high for latency-sensitive services. Therefore, it is recommended to use persistent connections to complete requests whenever possible. In HTTP 1.1, Long connections are also the default option. @@ -40,7 +41,7 @@ However, there is no silver bullet, as maintaining connections also consumes res Therefore, in some scenarios, long connections may not be suitable. For example, in a scenario where configurations need to be pulled periodically, the connection establishment delay may not have a significant impact on configurations, and it may be more appropriate to use short connections if horizontal scalability is a concern when the configuration center is under high load. -* **Packet Size** +- **Packet Size** The package size of a service depends on the actual business scenario. In HTTP scenarios, data can be placed in query, path, header, body, etc., and different locations have different effects on parsing. HTTP header is an identifier protocol, and the framework does not know how many headers there are until it finds a specific identifier. Therefore, the framework needs to receive all the headers before it can complete the parsing, @@ -49,7 +50,7 @@ which is not very friendly to the framework's memory model. [Hertz][Hertz] has a Meanwhile, in the internal statistics of online services at ByteDance, it was found that most packages are within 1K (but too small packages have no practical significance, such as a fixed return of "hello world"). At the same time, there is no upper limit on the size of large packages, and various package sizes are involved. Therefore, [Hertz][Hertz] has focused on optimizing the performance (throughput and latency) of packages within the most commonly used range of 128k or less. -* **Concurrency Quantity** +- **Concurrency Quantity** Each instance may have multiple upstreams and will not only accept requests from a single instance. Moreover, HTTP 1 doesn't support multiplexing, and each connection can only handle one request at a time. Therefore, the Server needs to accept multiple connections and process them simultaneously. @@ -69,12 +70,12 @@ For example, in a real-world scenario, would you create a project that only resp Before conducting load testing, consider your actual usage scenarios, such as: -* **Long vs Short Connections**: Determine whether using long or short connections is more suitable for your scenario. -* **Estimating Connection Usage**: If using long connections and connection usage is high (which is the case in most scenarios), use the default configuration. +- **Long vs Short Connections**: Determine whether using long or short connections is more suitable for your scenario. +- **Estimating Connection Usage**: If using long connections and connection usage is high (which is the case in most scenarios), use the default configuration. If connection usage is low, consider adding the configuration option **`server.WithIdleTimeout(0)`** to modify the goroutine per connection model to a coroutine pool model and conduct comparative testing. -* **Determining Data Location and Size**: As mentioned earlier, data in different locations (such as query, header, body, etc.) and of different sizes can affect the framework's performance. +- **Determining Data Location and Size**: As mentioned earlier, data in different locations (such as query, header, body, etc.) and of different sizes can affect the framework's performance. If the performance of all frameworks is similar, consider using a different data transmission location. -* **Determining Concurrency Quantity**: Some services are lightweight on business logic but heavy on framework, resulting in high framework concurrency. +- **Determining Concurrency Quantity**: Some services are lightweight on business logic but heavy on framework, resulting in high framework concurrency. Conversely, some services are heavy on business logic but light on framework, resulting in low framework concurrency. If you just want to test the performance of the framework, you can use the common scenario: **long connection, high connection usage, 1k body, 100 concurrency**, and so on. @@ -91,7 +92,6 @@ Some load testing projects usually conduct load testing for Client and Server pr If you want to conduct load testing the Server, you should give the Client as many resources as possible and push the Server to the limit, and vice versa. If both the Client and Server are only given 4 cores for load testing, developers will not be able to determine the performance data under which perspective, let alone provide actual reference for online services. - ### Use Dedicated CPUs Although online applications usually share CPUs among multiple processes, in a load testing scenario, both the Client and Server processes are extremely busy. Sharing CPUs at this time will result in a large number of context switches, which will make the data less reliable and prone to large fluctuations. @@ -105,14 +105,15 @@ In addition, if conditions permit, using physical machines instead of virtual ma On the premise of meeting the above requirements, we compared the load testing result of multiple frameworks based on the latest version. The pressure test code is in the [hertz-benchmark][hertz-benchmark] repository. With the goal of fully filling the load of Server, [Hertz] has the lowest P99 latency of all the frameworks tested, and the throughput is also in the first tier and under continuous optimization. -* CPU: AMD EPYC 7Y83 64-Core Processor 2.7GHz - * limits: server 4-CPUs,client 16-CPUS -* OS:Debian GNU/Linux 10 (buster) -* Go 1.19 -* [hertz v0.3.2](https://github.com/cloudwego/hertz/releases/tag/v0.3.2),[fasthttp v1.40.0](https://github.com/valyala/fasthttp/releases/tag/v1.40.0), +- CPU: AMD EPYC 7Y83 64-Core Processor 2.7GHz + - limits: server 4-CPUs,client 16-CPUS +- OS:Debian GNU/Linux 10 (buster) +- Go 1.19 +- [hertz v0.3.2](https://github.com/cloudwego/hertz/releases/tag/v0.3.2),[fasthttp v1.40.0](https://github.com/valyala/fasthttp/releases/tag/v1.40.0), [gin v1.8.1](https://github.com/gin-gonic/gin/releases/tag/v1.8.1),[fiber v2.38.1](https://github.com/gofiber/fiber/releases/tag/v2.38.1) ![image](/img/blog/Hertz-benchmark/1.png) +

Comparison of throughput and latency of four frameworks

![image](/img/blog/Hertz-benchmark/2.png) diff --git a/content/en/blog/news/Hertz_Open_Source/index.md b/content/en/blog/news/Hertz_Open_Source/index.md index 2699380541..f1297c56c8 100644 --- a/content/en/blog/news/Hertz_Open_Source/index.md +++ b/content/en/blog/news/Hertz_Open_Source/index.md @@ -3,10 +3,19 @@ date: 2022-06-21 title: "Hertz, an Ultra Large Scale Enterprise-Level Microservice HTTP Framework, is Now Officially Open Source!" projects: ["Hertz"] linkTitle: "Hertz, an Ultra Large Scale Enterprise-Level Microservice HTTP Framework, is Now Officially Open Source!" -keywords: ["CloudWeGo", "http framework", "large scale high performance", "Hertz", "ByteDance Open Source", "open source"] +keywords: + [ + "CloudWeGo", + "http framework", + "large scale high performance", + "Hertz", + "ByteDance Open Source", + "open source", + ] description: "This article introduces Hertz, the official open source ultra-large-scale enterprise-level microservice HTTP framework developed by ByteDance" author: CloudWeGo Team --- + Today, after more than a year of internal use and iteration at ByteDance, **[Hertz](https://github.com/cloudwego/hertz)**, a **high-performance enterprise-level HTTP framework**, is officially open-sourced on [CloudWeGo](https://github.com/cloudwego)! Hertz has become the largest HTTP framework within ByteDance, with more than **10,000** online services and a peak QPS (Query Per Second) of more than **40 million**. It has the characteristics of high usability, easy expansion, and low latency. For the ByteDance service framework team and CloudWeGo, [Hertz](https://github.com/cloudwego/hertz) will not only be an open source project, but also a real ultra-large-scale enterprise-level practice. Project website: https://github.com/cloudwego/hertz @@ -14,6 +23,7 @@ Project website: https://github.com/cloudwego/hertz In the future, ByteDance infrastructure team will iterate on the Hertz open source library, maintaining a unified codebase both internally and externally, and facilitating iterative evolution to enhance user experience. ## Hertz Overview + [Hertz](https://github.com/cloudwego/hertz) is a high-usability, high-performance, highly extensible, and low-latency Golang HTTP framework that assists developers in building microservices. Originally, the HTTP framework used within ByteDance was an encapsulation of the Gin framework, which offered advantages such as ease of use and a comprehensive ecosystem. However, as the internal business continued to grow, the demand for high performance and versatility rapidly increased. [Gin](https://github.com/gin-gonic/gin), being a secondary development of Golang's native net/http, faced limitations in terms of on-demand expansion and performance optimization. In order to meet the evolving business needs and effectively serve major functions, the ByteDance service framework team embarked on research based on their self-developed networking library, [Netpoll](https://github.com/cloudwego/netpoll). This research led to the development of the internal framework, Hertz, which exhibits enhanced performance and stability when faced with enterprise-level requirements. Hertz also facilitates business development and addresses evolving technical requirements. In July 2021, Hertz officially launched version 1.0. @@ -22,37 +32,47 @@ After over a year of internal usage at ByteDance, the Hertz framework has become In such a large-scale scenario, Hertz demonstrates remarkable stability and performance. Bugs and kernel issues are promptly identified and rectified. Furthermore, Hertz maintains a set of codes both internally and externally, providing a strong foundation for the open-source Hertz framework. ## Features + Key features of Hertz include: ### Stability - In a large-scale environment, Hertz exercises caution during every PR integration and release. Great care is taken to avoid any potential losses, which can amount to millions or even more. A standardized PR and release process has been formulated, requiring review by experienced developers for every code merge. Each PR and version release is to be tested for a period of time, and fully tested. Various testing scenarios, including compatibility, high concurrency, and package size, are employed to minimize risks. + +In a large-scale environment, Hertz exercises caution during every PR integration and release. Great care is taken to avoid any potential losses, which can amount to millions or even more. A standardized PR and release process has been formulated, requiring review by experienced developers for every code merge. Each PR and version release is to be tested for a period of time, and fully tested. Various testing scenarios, including compatibility, high concurrency, and package size, are employed to minimize risks. ### High Usability - Hertz prioritizes the ability to write correct code quickly during development. When designing the API, Hertz considers user usage habits and draws inspiration from the industry's mainstream framework API usage. Continuous iteration and user feedback contribute to the framework's refinement. For instance, many users hope that the Client also has the ability to trace. For this reason, Hertz Client supports middleware capabilities. Additionally, the Client supports stream processing in proxy scenarios. Middleware and stream processing are designed with the user's actual habits in mind, promoting faster development of correct code. Hertz also provides a one-click command-line tool for code generation, enhancing the framework's ease of use. + +Hertz prioritizes the ability to write correct code quickly during development. When designing the API, Hertz considers user usage habits and draws inspiration from the industry's mainstream framework API usage. Continuous iteration and user feedback contribute to the framework's refinement. For instance, many users hope that the Client also has the ability to trace. For this reason, Hertz Client supports middleware capabilities. Additionally, the Client supports stream processing in proxy scenarios. Middleware and stream processing are designed with the user's actual habits in mind, promoting faster development of correct code. Hertz also provides a one-click command-line tool for code generation, enhancing the framework's ease of use. + ### Easy expandability - Hertz employs a layered design, offering a range of interfaces and default extension implementations for users to expand upon. Details regarding [Hertz extension](/zh/docs/hertz/tutorials/framework-exten/) can be found on the [CloudWeGo official website](/). The framework's layered design enhances its scalability. Currently, only stable capabilities are open-sourced, with more planned for the future. Please refer to the [Hertz roadmap](https://github.com/cloudwego/hertz/blob/develop/ROADMAP.md) for further details. + +Hertz employs a layered design, offering a range of interfaces and default extension implementations for users to expand upon. Details regarding [Hertz extension](/zh/docs/hertz/tutorials/framework-exten/) can be found on the [CloudWeGo official website](/). The framework's layered design enhances its scalability. Currently, only stable capabilities are open-sourced, with more planned for the future. Please refer to the [Hertz roadmap](https://github.com/cloudwego/hertz/blob/develop/ROADMAP.md) for further details. ### Low latency - Hertz utilizes the internally developed high-performance network library, [Netpoll](https://github.com/cloudwego/netpoll), by default. In certain special scenarios, Hertz demonstrates advantages in terms of QPS and delay compared to the go net package. - - For performance data, please refer to the Echo data in the figure below. Internal testing has shown significant reduction in resource usage, including a **30%-60% decrease in CPU usage** for services predominantly utilizing frameworks and gateway services. For detailed performance data, please refer to: https://github.com/cloudwego/hertz-benchmark. + +Hertz utilizes the internally developed high-performance network library, [Netpoll](https://github.com/cloudwego/netpoll), by default. In certain special scenarios, Hertz demonstrates advantages in terms of QPS and delay compared to the go net package. + +For performance data, please refer to the Echo data in the figure below. Internal testing has shown significant reduction in resource usage, including a **30%-60% decrease in CPU usage** for services predominantly utilizing frameworks and gateway services. For detailed performance data, please refer to: https://github.com/cloudwego/hertz-benchmark. ![image](/img/blog/Hertz_Open_Source/Echo.png) ### Command line tool - Hertz provides a simple and user-friendly command-line tool called Hz. Users simply need to provide an Interface Definition Language (IDL). Based on the defined interface information, Hz can generate project scaffolding with a single click, enabling users to use Hertz out of the box. Additionally, Hz offers update capabilities, allowing users to update the scaffolding when changes are made to the IDL. Currently, Hz supports two IDL definitions: Thrift and Protobuf. The command-line tool provides a range of built-in options that can be tailored to individual needs. It relies on the official Protobuf compiler and the self-developed Thriftgo compiler, both of which support custom code plug-ins for generating templates that meet specific requirements. + +Hertz provides a simple and user-friendly command-line tool called Hz. Users simply need to provide an Interface Definition Language (IDL). Based on the defined interface information, Hz can generate project scaffolding with a single click, enabling users to use Hertz out of the box. Additionally, Hz offers update capabilities, allowing users to update the scaffolding when changes are made to the IDL. Currently, Hz supports two IDL definitions: Thrift and Protobuf. The command-line tool provides a range of built-in options that can be tailored to individual needs. It relies on the official Protobuf compiler and the self-developed Thriftgo compiler, both of which support custom code plug-ins for generating templates that meet specific requirements. Since the launch of Hertz, the internal response has been excellent. It has been extensively used in various scenarios including front-end and back-end communication, as well as gateway, upload, download, and proxy scenarios. The supported interaction modes encompass not only ping-pong but also streaming and chunk interactions. Hertz supports multiple protocols such as HTTP1, HTTP2, and Websocket. Managing such complex interaction scenarios and modes poses significant challenges to the usability and stability of Hertz's Server and Client components. In response, Hertz promptly addresses user needs and establishes a stability test service that simulates real-world and complex online scenarios as accurately as possible. With a high single-test coverage rate, Hertz ensures that the code logic functions normally and reliably. ## Internal and external version maintenance + ByteDance possesses a comprehensive internal microservice system, and the team places significant emphasis on open source development and commitment. This principle applies to both the Hertz project and CloudWeGo's [Kitex](https://github.com/cloudwego/kitex) project, ensuring consistency between internal and external versions. The core capabilities of the project have been migrated to the open source library, with only one internal layer of encapsulation. This approach facilitates enterprise upgrades without disruptions, thus guaranteeing long-term maintenance commitments. All open source features will be released after undergoing internal stability verification. Moving forward, the team will continue to iterate based on the Hertz open source library, promptly addressing community needs and issues to enhance user experience and ensure a reliable framework. Hertz developers can also leverage its flexible expansion capabilities to meet specific business requirements. Furthermore, external developers are encouraged to [contribute](https://github.com/cloudwego/hertz/blob/develop/CONTRIBUTING.md) to the community, collaboratively constructing an HTTP framework with a comprehensive ecosystem, exceptional performance, and user-friendly features. ## Roadmap + For the infrastructure team, Hertz represents not only an open source project but also a genuine ultra-large-scale enterprise-level practice. By open sourcing Hertz, our aim is to enrich the Golang middleware system within the cloud-native community, enhance the CloudWeGo ecosystem, and enable more developers and enterprises to build cloud-native large-scale distributed systems. We aspire to provide modern, resource-efficient technical solutions. As mentioned earlier, Hertz has currently open sourced only the internally verified stable components. However, we intend to further enhance the framework by pursuing the following objectives: + - **Cloud native capability support**: Integrate support for the xDS API to dynamically obtain service configurations from Istio. - **Multi-protocol support**: Hertz currently only open-sources HTTP1. In the future, we will open-source other protocols, such as HTTP2, Websocket, ALPN, etc., to provide developers with support for micro-service requirements in more scenarios. If you have a need, you can also submit an issue and let us know your needs for quick support. - **Improved command-line tools**: Continuously iterate on Hz, integrating various commonly used middleware and providing modular construction capabilities, enabling users to select the required components as needed. @@ -62,6 +82,7 @@ As mentioned earlier, Hertz has currently open sourced only the internally verif We welcome everyone to [contribute](https://github.com/cloudwego/hertz/blob/develop/CONTRIBUTING.md) by submitting issues and PRs to [Hertz](https://github.com/cloudwego/hertz), fostering collaborative development. We eagerly anticipate the involvement of more developers and anticipate Hertz aiding enterprises in swiftly constructing cloud-native architectures. Enterprise users are invited to migrate and utilize Hertz, and we will provide dedicated technical support and communication. Feel free to [join our Discord community](https://discord.gg/jceZSE7DsW) for further consultations and assistance. ## Related Links + - Project [address](https://github.com/cloudwego/hertz) - Community [ecosystem](https://github.com/hertz-contrib) - Hertz benchmark [blog](/blog/2023/02/24/getting-started-with-hertz-performance-testing-guide/) diff --git a/content/en/blog/news/Introducing CloudWeGo/index.md b/content/en/blog/news/Introducing CloudWeGo/index.md index 11e28ed095..a874602c80 100644 --- a/content/en/blog/news/Introducing CloudWeGo/index.md +++ b/content/en/blog/news/Introducing CloudWeGo/index.md @@ -3,7 +3,16 @@ date: 2023-06-15 title: "CloudWeGo: A leading practice for building enterprise cloud native middleware!" projects: ["CloudWeGo"] linkTitle: "CloudWeGo: A leading practice for building enterprise cloud native middleware!" -keywords: ["CloudWeGo", "middleware", "Kitex", "microservice framework", "ByteDance Open Source", "open source", "cloud native"] +keywords: + [ + "CloudWeGo", + "middleware", + "Kitex", + "microservice framework", + "ByteDance Open Source", + "open source", + "cloud native", + ] description: "This article provides an overview of CloudWeGo" author: Vini Jaiswal --- diff --git a/content/en/blog/news/Kitex_Proxyless_OpenTelemetry/index.md b/content/en/blog/news/Kitex_Proxyless_OpenTelemetry/index.md index 59d0e398bc..19cbe5b212 100644 --- a/content/en/blog/news/Kitex_Proxyless_OpenTelemetry/index.md +++ b/content/en/blog/news/Kitex_Proxyless_OpenTelemetry/index.md @@ -9,23 +9,23 @@ The purpose is to demonstrate how to use xDS to realize traffic lane in a practi author: CoderPoet, Guangming Luo --- -> Preface: Kitex Proxyless enables the Kitex service to interact directly with istiod without envoy sidecar. It dynamically obtains service governance rules -> delivered by the control plane based on the xDS protocol and converts them to Kitex rules to implement some service governance functions, such as traffic routing. -> Based on Kitex Proxyless, Kitex can be managed by Service Mesh without sidecar. Besides, the governance rule Spec, governance control plane, governance delivery protocol, +> Preface: Kitex Proxyless enables the Kitex service to interact directly with istiod without envoy sidecar. It dynamically obtains service governance rules +> delivered by the control plane based on the xDS protocol and converts them to Kitex rules to implement some service governance functions, such as traffic routing. +> Based on Kitex Proxyless, Kitex can be managed by Service Mesh without sidecar. Besides, the governance rule Spec, governance control plane, governance delivery protocol, > and heterogeneous data governance capability can be unified under multiple deployment modes. By rewriting the bookinfo project using Kitex and Hertz, it demonstrates how to implement a traffic lane using xDS protocol. ## 01 Introduction ### **Kitex Proxyless** -[Kitex][Kitex] is a Golang RPC framework open-sourced by ByteDance that already natively supports the xDS standard protocol and can be managed by Service Mesh in Proxyless way. -Refer to this doc for detailed design: [Proposal: Kitex support xDS Protocol](https://github.com/cloudwego/kitex/issues/461). +[Kitex][Kitex] is a Golang RPC framework open-sourced by ByteDance that already natively supports the xDS standard protocol and can be managed by Service Mesh in Proxyless way. +Refer to this doc for detailed design: [Proposal: Kitex support xDS Protocol](https://github.com/cloudwego/kitex/issues/461). Official doc is also available here at [Kitex/Tutorials/Advanced Feature/xDS Support](/docs/kitex/tutorials/advanced-feature/xds/) -Kitex Proxyless Simply means that Kitex services can interact directly with istiod without envoy sidecar and dynamically obtain service governance rules delivered by the control plane based on the xDS protocol. +Kitex Proxyless Simply means that Kitex services can interact directly with istiod without envoy sidecar and dynamically obtain service governance rules delivered by the control plane based on the xDS protocol. And those rules will be translated into Kitex corresponding rules to implement some service governance functions (such as traffic routing which is the focus of this blog). -Based on Kitex Proxyless, Kitex application can be managed by Service Mesh in a unified manner without sidecar, and thus the governance rule Spec, governance control plane, +Based on Kitex Proxyless, Kitex application can be managed by Service Mesh in a unified manner without sidecar, and thus the governance rule Spec, governance control plane, governance delivery protocol, and heterogeneous data governance capability can be unified under multiple deployment modes. ![image](/img/blog/Kitex_Proxyless/unify_architecture.svg) @@ -46,13 +46,14 @@ Specific procedure: 1. Aware of LDS changes and extract the Filter Chain and inline RDS in the LDS of the target service. 1. Aware of RDS changes and obtain the route configuration of the target service based on VirtualHost and ServiceName matching. (Prefix, suffix, exact, and wildcard are supported) 1. The routing rules in the matched RDS are traversed and processed. The routing rules are divided into two parts (refer to the routing specification definition) : + - Match: - - Path(required): Extract Method from rpcinfo for matching; - - HeaderMatcher(optional): Extract the corresponding metadata KeyValue from the metainfo and match it. + - Path(required): Extract Method from rpcinfo for matching; + - HeaderMatcher(optional): Extract the corresponding metadata KeyValue from the metainfo and match it. - Route: - - Cluster :Standard Cluster. - - WeightedClusters(Weight routing) : cluster is selected according to weight within MW. - - Write the selected Cluster to the EndpointInfo.Tag for later service discovery. + - Cluster :Standard Cluster. + - WeightedClusters(Weight routing) : cluster is selected according to weight within MW. + - Write the selected Cluster to the EndpointInfo.Tag for later service discovery. As you can see, traffic routing is a process of selecting the corresponding SubCluster according to certain rules. @@ -60,32 +61,32 @@ As you can see, traffic routing is a process of selecting the corresponding SubC Based on traffic routing capability, we can extend many usage scenarios, such as: A/B testing, canary release, blue-green release, etc., and the focus of this paper: Traffic Lane. -The traffic lane can be understood as splitting a group of service instances in a certain way (such as deployment environment), and based on the routing capability and global metadata, +The traffic lane can be understood as splitting a group of service instances in a certain way (such as deployment environment), and based on the routing capability and global metadata, so that traffic can flow in the specified service instance lanes in accordance with the exact rules (logically similar to lanes in a swimming pool). Traffic lane can be used for full-path grey release. -In Istio we typically group instances with DestinationRule subset, splitting a service into multiple subsets (e.g. Based on attributes such as version and region) +In Istio we typically group instances with DestinationRule subset, splitting a service into multiple subsets (e.g. Based on attributes such as version and region) and then work with VirtualService to define the corresponding routing rules and route the traffic to the corresponding subset. In this way, the single-hop routing capability in the lane is realized. -However, traffic routing capability alone is not enough to realize traffic lane. We need a good mechanism to accurately identify the traffic +However, traffic routing capability alone is not enough to realize traffic lane. We need a good mechanism to accurately identify the traffic and configure routing rules for each hop traffic based on this feature when a request spans multiple services. -As shown in the following figure: Suppose we want to implement a user request that is accurately route to the v1 version of service-b. +As shown in the following figure: Suppose we want to implement a user request that is accurately route to the v1 version of service-b. The first thought might be to put a `uid = 100` in the request header and configure the corresponding VirtualService to match the `uid = 100` in the header. ![image](/img/blog/Kitex_Proxyless/3.png) But it has several obvious drawbacks for this approach: -1. **Not common enough**: If a specific business attribute (such as uid) is used as a traffic route matching rule, the business attribute must be manually transmitted through the full path. +1. **Not common enough**: If a specific business attribute (such as uid) is used as a traffic route matching rule, the business attribute must be manually transmitted through the full path. This is highly intrusive to business and requires business cooperation. In addition, when we want to use other business attributes, all services on the full path need to change to adapt. Therefore, it is a very unusual practice. -1. Routing rules are prone to frequent changes, resulting in **rule overcrowding**. Routing rules are identified by specific business attributes (for example: uid) is used as a traffic route matching rule. +1. Routing rules are prone to frequent changes, resulting in **rule overcrowding**. Routing rules are identified by specific business attributes (for example: uid) is used as a traffic route matching rule. If you want to change a business attribute or set a routing rule for other users, you need to modify the original routing rule or repeatedly define multiple routing rules for different business attributes, which easily causes route rule overcrowding and is difficult to maintain. Therefore, in order to achieve uniform traffic routing across the full path, we also need to use a more general traffic dyeing and the capability to transmit the dye identifier through the full path. ### Traffic Dyeing -Traffic dyeing refers to marking the request traffic with a special identifier and carrying this identifier in the full request path. +Traffic dyeing refers to marking the request traffic with a special identifier and carrying this identifier in the full request path. The so-called traffic lane means that all services in the path sets traffic routing rules based on the uniform gray traffic dyeing identifier so that the traffic can be accurately controlled in different lanes. Usually, traffic dyeing is done at the gateway layer, and the metadata in the original request is converted into corresponding dye identifiers according to certain rules (conditions and proportions). @@ -93,7 +94,7 @@ Usually, traffic dyeing is done at the gateway layer, and the metadata in the or - **Dyeing by conditions**: when the request metadata meets certain conditions (such as `uid = 100` in the request header and cookie matching), the current request is marked with a dye identifier. - **Dyeing by proportions**: the request is marked with a dye identifier in proportion. -With a unified traffic dyeing mechanism, we do not need to care about specific business attribute identifiers when configuring routing rules. We only need to configure routes based on the dye identifiers. +With a unified traffic dyeing mechanism, we do not need to care about specific business attribute identifiers when configuring routing rules. We only need to configure routes based on the dye identifiers. The specific service attributes are abstracted into conditional dyeing rules to be more universal. Even if the business attributes change, the routing rules do not need to change frequently. #### Dye Identifier Transmitting @@ -115,7 +116,7 @@ The demo is a rewriting of the [Istio Bookinfo](https://istio.io/latest/zh/docs/ - Use **istiod** as the xDS server and the entry for CRD configuration and delivery. - Use **wire** to implement dependency injection; - Use **opentelemetry** to implement full path tracing; -- Use [Kitex-xds](https://github.com/kitex-contrib/xds) and **opentelemetry baggage** to implement a traffic lane in proxyless mode; +- Use [Kitex-xds](https://github.com/kitex-contrib/xds) and **opentelemetry baggage** to implement a traffic lane in proxyless mode; - Implement a [Bookinfo](https://github.com/cloudwego/biz-demo/blob/main/bookinfo/README_CN.md) UI using **arco-design** and **react**. ### Business Architecture @@ -170,7 +171,7 @@ Take service `reviews` as an example. You only need to label the corresponding p ### Traffic Routing Rules -The gateway has already dyed the request header with `uid=100` and automatically loaded `env=dev` baggage, +The gateway has already dyed the request header with `uid=100` and automatically loaded `env=dev` baggage, so we only need to match the route according to the header. Here is an example of the route rule configuration: ![image](/img/blog/Kitex_Proxyless/10.png) @@ -195,11 +196,11 @@ Click the refresh button again, you can find that the request hits the branch la ## 04 Summary and Outlook -So far, we have implemented a complete full-path traffic lane based on Kitex Proxyless and OpenTelemetry. +So far, we have implemented a complete full-path traffic lane based on Kitex Proxyless and OpenTelemetry. And we can set corresponding routing rules for Kitex based on Istio standard governance rule Spec without Envoy sidecar. -In addition to traffic routing capabilities, Kitex Proxyless is also continuously iterating and optimizing to meet more requirements for data plane governance capabilities. -As an exploration and practice of Service Mesh data plane, Proxyless not only can enrich the deployment form of data plane, but also hopes to continuously polish [Kitex][Kitex], +In addition to traffic routing capabilities, Kitex Proxyless is also continuously iterating and optimizing to meet more requirements for data plane governance capabilities. +As an exploration and practice of Service Mesh data plane, Proxyless not only can enrich the deployment form of data plane, but also hopes to continuously polish [Kitex][Kitex], enhance its ability in open source ecological compatibility, and create a more open and inclusive microservice ecosystem. ## 05 Relevant Project @@ -213,7 +214,7 @@ Here is a list of the projects involved in the demo: - kitex-opentelemetry: https://github.com/kitex-contrib/obs-opentelemetry - hertz-opentelemetry: https://github.com/hertz-contrib/obs-opentelemetry -This demo has been submitted in the biz-demo repository, and will be optimised continuously. biz-demo will include some complete demos based on CloudWeGo technology stack with certain business scenarios. +This demo has been submitted in the biz-demo repository, and will be optimised continuously. biz-demo will include some complete demos based on CloudWeGo technology stack with certain business scenarios. The original intention is to provide valuable references for enterprise users to use CloudWeGo in production. Contributors are always welcomed to participate in the contribution of CloudWeGo biz-demo. Let's try something fun together. [Kitex]: https://github.com/cloudwego/kitex diff --git a/content/en/blog/news/Kitex_perf_optimize_practices/index.md b/content/en/blog/news/Kitex_perf_optimize_practices/index.md index 4bc80c50af..51ada77284 100644 --- a/content/en/blog/news/Kitex_perf_optimize_practices/index.md +++ b/content/en/blog/news/Kitex_perf_optimize_practices/index.md @@ -7,26 +7,33 @@ keywords: ["Kitex", "Optimization", "Netpoll", "Thrift", "Serialization"] description: "This blog introduces the performance optimization practice of Bytedance Go RPC framework Kitex, which includes Netpoll, Thrift, serialization and so on." author: Hchen, Pure White, Simon Wang, bytexw --- + ## Preface + Kitex is the next generation high-performance and extensible Go RPC framework developed by ByteDance Service Framework Team. Compared with other RPC frameworks, in addition to its rich features for service governance, it has the following characteristics: integrated with the self-developed network library - Netpoll; supports multiple Message Protocols (Thrift, Protobuf) and Interactive Models (Ping-Pong, Oneway, Streaming); provides a more flexible and extensible code generator. -Currently, Kitex has been widely used by the major lines of business in ByteDance, and statistics shows that the number of service access is up to 8K. We've been continuously improving Kitex's performance since its launch. This article will share our work on optimizing Netpoll and serialization. +Currently, Kitex has been widely used by the major lines of business in ByteDance, and statistics shows that the number of service access is up to 8K. We've been continuously improving Kitex's performance since its launch. This article will share our work on optimizing Netpoll and serialization. -## Optimization of the Network Library - Netpoll -Netpoll, the self-developed network library based on Epoll. Compared with the previous version and the go net library, its performance has been significantly improved. Test results indicated that compared with the last version (2020.05), the latest version (2020.12) has ↑30% throughput capacity, ↓25% AVG latency, and ↓67% TP99 . Its performance is far better than the Go Net library. Below, we'll share two solutions that can significantly improve its performance. +## Optimization of the Network Library - Netpoll + +Netpoll, the self-developed network library based on Epoll. Compared with the previous version and the go net library, its performance has been significantly improved. Test results indicated that compared with the last version (2020.05), the latest version (2020.12) has ↑30% throughput capacity, ↓25% AVG latency, and ↓67% TP99 . Its performance is far better than the Go Net library. Below, we'll share two solutions that can significantly improve its performance. ### Optimizing Scheduling Delays When Calling "epoll_wait" + When Netpoll was newly released, it encountered the problem of low AVG latency but high TP99. Through our research and analysis on "epoll_wait", we found that such a problem could be mitigated by integrating "polling" and "event trigger". With such improvements in scheduling strategy, the latency can be reduced considerably. Let's have a look at the "syscall.EpollWait" method provided by Go first: + ```go func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) ``` -Three parameters are provided here, they represent "epoll fd", “callback events”, and "milliseconds to wait" respectively. Only "msec" is dynamic. -Normally, we would set "msec = -1" when we are actively calling "EpollWait", as we want to wait for the event infinitely. In fact, many open-source net libraries were also using it in this way. But our research showed that setting "msec =-1" was not the optimal solution. +Three parameters are provided here, they represent "epoll fd", “callback events”, and "milliseconds to wait" respectively. Only "msec" is dynamic. + +Normally, we would set "msec = -1" when we are actively calling "EpollWait", as we want to wait for the event infinitely. In fact, many open-source net libraries were also using it in this way. But our research showed that setting "msec =-1" was not the optimal solution. The kernel source (below) of "epoll_wait" shows that setting "msec = -1" arises extra "fetch_events" checks than setting "msec = 0", and therefore consumes more time. + ```go static int ep_poll(struct eventpoll *ep, struct epoll_event __user *events, int maxevents, long timeout) @@ -47,16 +54,18 @@ fetch_events: send_events: ... ``` -The Benchmark shows that when an event is triggered, setting "msec = 0" is about 18% faster than setting "msec = -1". Thus, when triggering complex events, setting "msec = 0" is obviously a better choice. + +The Benchmark shows that when an event is triggered, setting "msec = 0" is about 18% faster than setting "msec = -1". Thus, when triggering complex events, setting "msec = 0" is obviously a better choice. |Benchmark|time/op|bytes/op| |:----|:----|:----| |BenchmarkEpollWait, msec=0|270 ns/op|0 B/op| |BenchmarkEpollWait, msec=-1|328 ns/op|0 B/op| -|EpollWait Delta|-17.68%|~| +|EpollWait Delta|-17.68%|~| However, setting "msec = 0" would lead to infinite polling when no event is triggered, consumes lots of resources. Taking the previously mentioned factors into account, it's preferred to set "msec = 0" when an event is triggered and "msec = -1" when no event is triggered to reduce polling. The pseudocode is demonstrated as follows: + ```go var msec = -1 for { @@ -69,9 +78,11 @@ for { ... } ``` + Nevertheless, our experiments have proved that the improvement is insignificant. Setting "msec = 0" merely reduces the delay of a single call by 50ns, which is not a considerable improvement. If we want to further reduce latency, adjustment must be made in Go runtime scheduling. Thus, let's further explore this issue: -In the pseudocode above, setting "msec= -1" with no triggered event, and "continue" directly will immediately execute "EpollWait" again. Since there is no triggered event while "msec = -1", the current "goroutine" will block and be switched by "P" passively. However, it is less efficient, and we can save time if we actively switch "goroutine" for "P" before "continue". So we modified the above pseudocode as follows: +In the pseudocode above, setting "msec= -1" with no triggered event, and "continue" directly will immediately execute "EpollWait" again. Since there is no triggered event while "msec = -1", the current "goroutine" will block and be switched by "P" passively. However, it is less efficient, and we can save time if we actively switch "goroutine" for "P" before "continue". So we modified the above pseudocode as follows: + ```go var msec = -1 for { @@ -85,10 +96,13 @@ for { ... } ``` + The test results of the modified code showed that throughput ↑12% and TP99 ↓64%. The latency was significantly reduced. -### Utilizing "unsafe.Pointer" +### Utilizing "unsafe.Pointer" + Through further study of "epoll_wait", we find that the "syscall.EpollWait" published by Go and the "epollwait" used by "runtime" are two different versions, as they use different "EpollEvent". They are demonstrated as follows: + ```go // @syscall type EpollEvent struct { @@ -102,29 +116,36 @@ type epollevent struct { data [8]byte // unaligned uintptr } ``` -As we can see, the "epollevent" used by "runtime" is the original structure defined by "epoll" at system layer. The published version encapsulates it and splits "epoll_data(epollevent.data)" into two fixed fields: "Fd" and "Pad". For "runtime", in its source code we found the following logic: + +As we can see, the "epollevent" used by "runtime" is the original structure defined by "epoll" at system layer. The published version encapsulates it and splits "epoll_data(epollevent.data)" into two fixed fields: "Fd" and "Pad". For "runtime", in its source code we found the following logic: + ```go *(**pollDesc)(unsafe.Pointer(&ev.data)) = pd pd := *(**pollDesc)(unsafe.Pointer(&ev.data)) ``` + Obviously, "runtime" uses "epoll_data(&ev.data)" to store the pointer of the corresponding structure (pollDesc) of "fd" directly. Thus, when an event is triggered, the "struct" object can be found directly with the corresponding logic being executed. However, the external version can only obtain the encapsulated "fd" parameters. So it needs to introduce additional "Map" to manipulate the "struct" object, and the performance will be diminished. -Therefore, we abandoned "syscall.EpollWait" and designed our own "EpollWait" call by referring to "runtime". We also use "unsafe.Pointer" to access "struct" objects. The test results showed that our "EpollWait" call contributed to ↑10% throughput and ↓10% TP99, which has significantly improved efficiency. +Therefore, we abandoned "syscall.EpollWait" and designed our own "EpollWait" call by referring to "runtime". We also use "unsafe.Pointer" to access "struct" objects. The test results showed that our "EpollWait" call contributed to ↑10% throughput and ↓10% TP99, which has significantly improved efficiency. ## Serialization/Deserialization Optimization of Thrift + Serialization refers to the process of converting a data structure or object into a binary or textual form. Deserialization is the opposite process. A serialization protocol needs to be agreed during RPC communication. The serialization process is executed before the client sends requests. The bytes are transmitted to the server over the network, and the server will logic-process the bytes to complete an RPC request. Thrift supports "Binary", "Compact", and "JSON" serialization protocols. Since "Binary" is the most common protocol used in Bytedance, we will only discuss about "Binary" protocol. "Binary" protocol is "TLV" ("Type", "Length", "Value") encoded, that is, each field is described using "TLV" structure. It emphasizes that the "Value" can also be a "TLV" structure, where the "Type" and "Length" are fixed in length, and the length of "Value" is determined by the input value of "Length". The TLV coding structure is simple, clear, and scalable. However, since it requires the input of "Type" and "Length", there is extra memory overhead incurred. It wastes considerable memory especially when most fields are in base types. The performance of serialization and deserialization can be optimized from two dimensions - "time" & "space". To be compatible with the existing "binary" protocols, optimization in "space" seems to be infeasible. Improvement can only be made in "time", it includes: + - Reduce the frequency of operations on memory, notably memory allocation and copying. Try to pre-allocate memory to reduce unnecessary time consumption. - Reduce the frequency of function calls by adjusting code structure or using "inline" etc. ### Research on Serialization Strategy -Based on "go_serialization_benchmarks", we investigated a number of serialization schemes that performed well to guide the optimization of our serialization strategy. + +Based on "go_serialization_benchmarks", we investigated a number of serialization schemes that performed well to guide the optimization of our serialization strategy. Analysis of "protobuf", "gogoprotobuf", and "Cap 'n Proto" has provided us the following results: + - Considering I/O, the transmitted data is usually compressed in size during network transmission. "protobuf" uses "Varint" encoding and has good data compression capabilities in most scenarios. - "gogoprotobuf" uses precomputation to reduce memory allocations and copies during serialization. Thus, it eliminates the cost of system calls, locks and GC arisen from memory allocations. - "Cap 'n Proto" directly operates buffer, which also reduces memory allocations and copies. In addition, it also designs "struct pointer" in a way that processes fixed-length data and non-fixed-length data separately, which enables fast processing for fixed-length data. @@ -132,7 +153,9 @@ Analysis of "protobuf", "gogoprotobuf", and "Cap 'n Proto" has provided us the f For compatibility reasons, it is impossible to change the existing "TLV" encoding format, so data compression is not feasible. But finding 2 and 3 are inspiring to our optimization work, and in fact we have taken a similar approach. ### Approaches + #### Reducing Operations on Memory + **Buffer management** Both serialization and deserialization involve copying data from one piece of memory to another. It involves memory allocation and memory copying. Avoiding memory operations can reduce unnecessary overhead such as system calls, locks, and GC. @@ -143,13 +166,13 @@ Initially we simply used "sync.Pool" to multiplex the "LinkBufferNode" of netpol **Copy-free String / Binary** For some services, such as video-related services, during its request or return processes, large-size "Binary" data will be arisen, representing the processed video or image data. Meanwhile, some services will return large-size "String" data (such as full-text information, etc.). In this scenario, all the hot spots we see through the flame graph are on the copies of the data. So we thought, can we reduce the frequency of such copies? -The answer is positive. Since our underlying buffer is a linked list, it is easy to insert a node in the middle of the list. +The answer is positive. Since our underlying buffer is a linked list, it is easy to insert a node in the middle of the list. -![!image](/img/blog/buffer-linkerd-list.png) +![!image](/img/blog/buffer-linkerd-list.png) Thus, we have taken a similar approach, when a "string" or "binary" data exists during serialization processes. First, split the node's buffer into two segments and then insert the buffer of the "string" / "binary" objects in the middle correspondingly. This avoids the copy of large "string" / "binary" . -Furthermore, a copy will occur if we convert a string to "[]byte" using "[]byte(string)". Because "string" is immutable and "[]byte" is mutable in Golang language. "unsafe" is needed if you don't want to copy during the conversion: +Furthermore, a copy will occur if we convert a string to "[]byte" using "[]byte(string)". Because "string" is immutable and "[]byte" is mutable in Golang language. "unsafe" is needed if you don't want to copy during the conversion: ```go func StringToSliceByte(s string) []byte { @@ -161,21 +184,24 @@ func StringToSliceByte(s string) []byte { })) } ``` + The meaning of this demonstrated code is to take the address of the string first, and then give it a slice byte header, so that the "string" can be converted into "[]byte" without copying the data. Note that the resulting "[]byte" is not writable, or the behavior is undefined. **Pre-Calculation** Some services support transmissions of large data package, which incurs considerable serialization / deserialization overhead. Generally, large packages are associated with the large size of the container type. If the buffer can be pre-calculated, some O(n) operations can be reduced to O(1), and further reduce the frequency of function calls. In the case of large data packages, the number of memory allocation can also be greatly reduced, bringing considerable benefits. - Base types + - If the container element is defined as base type (bool, byte, i16, i32, i64, double), the total size can be pre-calculated during serialization as its size is fixed, and enough buffer can be allocated at once. The number of "malloc" operations of O(n) can be reduced to O(1), thus greatly reducing the frequency of "malloc" operations. Similarly, the number of "next" operations can be reduced during deserialization. -- Rearrangement of "Struct" Fields +- Rearrangement of "Struct" Fields + - The above optimizations are valid only for container elements that are defined as base types. Can they be optimized for "struct" elements? The answer is yes. - If there are fields of base type in "struct", we can pre-calculate the size of these fields, then allocate buffer for these fields in advance during serialization and write these fields in the first order. We can also reduce the frequency of "malloc". - Size calculation - The optimization mentioned above is for base types. If you first iterate over all the fields of the request during serialization, you can calculate the size of the entire request, allocate buffer in advance, and directly manipulate buffer during serialization and deserialization, so that the optimization effect can be achieved for non-base types. - - Define a new "codec" interface: + - Define a new "codec" interface: ```go type thriftMsgFastCodec interface { @@ -185,7 +211,7 @@ type thriftMsgFastCodec interface { } ``` - - Change the "Marshal" and "Unmarshal" interfaces accordingly: +- Change the "Marshal" and "Unmarshal" interfaces accordingly: ```go func (c thriftCodec) Marshal(ctx context.Context, message remote.Message, out remote.ByteBuffer) error { @@ -228,7 +254,9 @@ if msg, ok := data.(thriftMsgFastCodec); ok && message.PayloadLen() != 0 { ... } ``` - - Modify the generated code accordingly: + +- Modify the generated code accordingly: + ```go func (p *Demo) BLength() int { l := 0 @@ -257,22 +285,27 @@ func (p *Demo) FastWrite(buf []byte) int { offset += bthrift.Binary.WriteStructEnd(buf[offset:]) return offset } -``` +``` + #### Optimizing Thrift Encoding with SIMD + "list" is widely used in the company to carry the ID list, and the encoding method of "list" is highly consistent with the rule of vectorization. Thus, we use SIMD to optimize the encoding process of list. We implement "avx2" to improve the encoding process, and the improved results are significant. When dealing with large amounts of data, the performance can be improved by 6 times for i64 and 12 times for i32. In the case of small data volume, the improvement is more obvious, which achieves 10 times for i64 and 20 times for I32. #### Reducing Function Calls + **inline** The purpose of "inline" is to expand a function call during its compilation and replace it with the implementation of the function. It improves program performance by reducing the overhead of the function call. "inline" can't be implemented on all functions in Go. Run the process with the argument - (gflags="-m") to display the functions that are inlined. The following conditions cannot be inlined: + - A function containing a loop; - Functions that include: closure calls, select, for, defer, coroutines created by the go keyword; -- For Functions over a certain length, by default when parsing the AST, Go applies 80 nodes. Each node consumes one unit of inline budget. For example, a = a + 1 contains five nodes: AS, NAME, ADD, NAME, LITERAL. When the overhead of a function exceeds this budget, it cannot be inlined. +- For Functions over a certain length, by default when parsing the AST, Go applies 80 nodes. Each node consumes one unit of inline budget. For example, a = a + 1 contains five nodes: AS, NAME, ADD, NAME, LITERAL. When the overhead of a function exceeds this budget, it cannot be inlined. + +You can specify the intensity (go 1.9+) of the compiler's inlined code by specifying "-l" at compile time. But it is not recommended, as in our test scenario, it is buggy and does not work: -You can specify the intensity (go 1.9+) of the compiler's inlined code by specifying "-l" at compile time. But it is not recommended, as in our test scenario, it is buggy and does not work: ```go // The debug['l'] flag controls the aggressiveness. Note that main() swaps level 0 and 1, making 1 the default and -l disable. Additional levels (beyond -l) may be buggy and are not supported. // 0: disabled @@ -281,7 +314,9 @@ You can specify the intensity (go 1.9+) of the compiler's inlined code by specif // 3: (unassigned) // 4: allow non-leaf functions ``` -Although using "inline" can reduce the overhead of function calls, it may also lead to lower CPU cache hit rate due to code redundancy. Therefore, excessive usage of "inline" should not be blindly pursued, and specific analysis should be carried out based on "profile" results. + +Although using "inline" can reduce the overhead of function calls, it may also lead to lower CPU cache hit rate due to code redundancy. Therefore, excessive usage of "inline" should not be blindly pursued, and specific analysis should be carried out based on "profile" results. + ```bash go test -gcflags='-m=2' -v -test.run TestNewCodec 2>&1 | grep "function too complex" | wc -l 48 @@ -289,66 +324,72 @@ go test -gcflags='-m=2' -v -test.run TestNewCodec 2>&1 | grep "function too comp go test -gcflags='-m=2 -l=4' -v -test.run TestNewCodec 2>&1 | grep "function too complex" | wc -l 25 ``` -As you can see, from the output above, increasing the inline intensity does reduce the "function too complex". Following are the benchmark results: -|Benchmark|time/op|bytes/op|allocs/op| -|:----|:----|:----|:----| -|BenchmarkOldMarshal-4|309 µs ± 2%|218KB|11| -|BenchmarkNewMarshal-4|310 µs ± 3%|218KB|11| +As you can see, from the output above, increasing the inline intensity does reduce the "function too complex". Following are the benchmark results: + +| Benchmark | time/op | bytes/op | allocs/op | +| :-------------------- | :---------- | :------- | :-------- | +| BenchmarkOldMarshal-4 | 309 µs ± 2% | 218KB | 11 | +| BenchmarkNewMarshal-4 | 310 µs ± 3% | 218KB | 11 | -It reveals that turning on the highest level of inlining intensity does eliminate many functions that cannot be inlined due to "function too complex", but the test results show that the improvement is insignificant. +It reveals that turning on the highest level of inlining intensity does eliminate many functions that cannot be inlined due to "function too complex", but the test results show that the improvement is insignificant. ### Testing Results + We built benchmarks to compare performance before and after optimization, and here are the results. -Testing Environment: -Go 1.13.5 darwin/amd64 on a 2.5 GHz Intel Core i7 16GB - -**Small Data Size** - -Data size: 20KB - -|Benchmark|time/op|bytes/op|allocs/op| -|:----|:----|:----|:----| -|BenchmarkOldMarshal-4|138 µs ± 3%|25.4KB|19| -|BenchmarkNewMarshal-4|29 µs ± 3%|26.4KB|11| -|Marshal Delta|-78.97%|3.87%|-42.11%| -|BenchmarkOldUnmarshal-4|199 µs ± 3%|4720|1360| -|BenchmarkNewUnmarshal-4|94µs ± 5%|4700|1280| -|Unmarshal Delta|-52.93%|-0.24%|-5.38%| - -**Large Data Size** - -Data size: 6MB - -|Benchmark|time/op|bytes/op|allocs/op| -|:----|:----|:----|:----| -|BenchmarkOldMarshal-4|58.7ms ± 5%|6.96MB|3350| -|BenchmarkNewMarshal-4|13.3ms ± 3%|6.84MB|10| -|Marshal Delta|-77.30%|-1.71%|-99.64%| -|BenchmarkOldUnmarshal-4|56.6ms ± 3%|17.4MB|391000| -|BenchmarkNewUnmarshal-4|26.8ms ± 5%|17.5MB|390000| -|Unmarshal Delta|-52.54%|0.09%|-0.37%| +Testing Environment: +Go 1.13.5 darwin/amd64 on a 2.5 GHz Intel Core i7 16GB + +**Small Data Size** + +Data size: 20KB + +| Benchmark | time/op | bytes/op | allocs/op | +| :---------------------- | :---------- | :------- | :-------- | +| BenchmarkOldMarshal-4 | 138 µs ± 3% | 25.4KB | 19 | +| BenchmarkNewMarshal-4 | 29 µs ± 3% | 26.4KB | 11 | +| Marshal Delta | -78.97% | 3.87% | -42.11% | +| BenchmarkOldUnmarshal-4 | 199 µs ± 3% | 4720 | 1360 | +| BenchmarkNewUnmarshal-4 | 94µs ± 5% | 4700 | 1280 | +| Unmarshal Delta | -52.93% | -0.24% | -5.38% | + +**Large Data Size** + +Data size: 6MB + +| Benchmark | time/op | bytes/op | allocs/op | +| :---------------------- | :---------- | :------- | :-------- | +| BenchmarkOldMarshal-4 | 58.7ms ± 5% | 6.96MB | 3350 | +| BenchmarkNewMarshal-4 | 13.3ms ± 3% | 6.84MB | 10 | +| Marshal Delta | -77.30% | -1.71% | -99.64% | +| BenchmarkOldUnmarshal-4 | 56.6ms ± 3% | 17.4MB | 391000 | +| BenchmarkNewUnmarshal-4 | 26.8ms ± 5% | 17.5MB | 390000 | +| Unmarshal Delta | -52.54% | 0.09% | -0.37% | ## Copy-free Serialization + In some services with large request and response data, the cost of serialization and deserialization is high. There are two ways for optimization: + - Implement the optimization strategy on serialization and deserialization as described earlier. - Scheduling by copy-free serialization. ### Research on Copy-free Serilization + RPC through copy-free serialization, which originated from the "Cap 'n Proto" project of Kenton Varda. "Cap 'n Proto" provides a set of data exchange formats and corresponding codec libraries. In essence, "Cap 'n Proto" creates a bytes slice as buffer, and all read & write operations on data structures are directly operated on buffer. After reading & writing, information contained by the buffer is added to the head and can be sent directly. And the peer end can read it after receiving it. Since there is no Go structure as an intermediate storage, serialization and deserialization are not required. To briefly summarize the characteristics of "Cap 'n Proto": + - All data is read and written to a contiguous memory. - The serialization operation is preceded. "Get/Set" data and encoding process in parallel. - In the data exchange format, pointer ("offset" at the data memory) mechanism is used to store data at any location in the contiguous memory, so that data in the structure can be read and written in any order. - Fixed-size fields of a structure are rearranged so that they are stored in contiguous memory. - Fields with indeterminate size of a structure (e.g. list), are represented by a fixed-size pointer that stores information including the location of the data. - + First of all, "Cap 'n Proto" has no Go language structure as an intermediate carrier, which can reduce a copy. Then, "Cap 'n Proto" operates on a contiguous memory, and the read and write of coded data can be completed at once. Because of these two reasons, Cap 'n Proto has excellent performance. -Here are the benchmarks of "Thrift" and "Cap 'n Proto" for the same data structure. Considering that "Cap 'n Proto" presets the codec operation, we compare the complete process including data initialization. That is, structure data initialization + (serialization) + write buffer + read from buffer + (deserialization) + read from structure. +Here are the benchmarks of "Thrift" and "Cap 'n Proto" for the same data structure. Considering that "Cap 'n Proto" presets the codec operation, we compare the complete process including data initialization. That is, structure data initialization + (serialization) + write buffer + read from buffer + (deserialization) + read from structure. ```Thrift struct MyTest { @@ -360,60 +401,67 @@ struct MyTest { struct Ano { 1: i64 Num, } -``` +``` -|Benchmark|Iter|time/op|bytes/op|alloc/op| -|:----|:----|:----|:----|:----| -|BenchmarkThriftReadWrite|172|6855840 ns/op|3154209 B/op|545 allocs/op| -|BenchmarkCapnpReadWrite|1500|844924 ns/op|2085713 B/op|9 allocs/op| -|ReadWrite Delta|/|-87.68%|-33.88%|-98.35%| +| Benchmark | Iter | time/op | bytes/op | alloc/op | +| :----------------------- | :--- | :------------ | :----------- | :------------ | +| BenchmarkThriftReadWrite | 172 | 6855840 ns/op | 3154209 B/op | 545 allocs/op | +| BenchmarkCapnpReadWrite | 1500 | 844924 ns/op | 2085713 B/op | 9 allocs/op | +| ReadWrite Delta | / | -87.68% | -33.88% | -98.35% | (deserialization) + read data, depending on the size of data package,"Cap 'n Proto" performance is about 8-9 times better than "Thrift". Write data + (serialization), depending on the size of data package, "Cap 'n Proto" performance is approximately 2-8 times better than "Thrift". Overall performance of "Cap 'n Proto" is approximately 4-8 times better than "Thrift". Previously, we discussed the advantages of "Cap 'n Proto". We will then summarize some problems existing in "Cap 'n Proto": + - One problem with the contiguous memory of Cap 'n Proto is that when the data of variable size is resized, and the required space is larger than the original space, the space of the original data can only be reallocated later. As a result, the original space becomes a hole that cannot be removed. This problem gets worse as the call link is resized, and can only be solved with strict constraints throughout the link: avoid resizing variable size fields, and when resize is necessary, rebuild a structure and make a deep copy of the data. - "Cap 'n Proto" has no Go language structure as an intermediate carrier, so all fields can only be read and written through the interface, resulting in poor user experience. ### Thrift Protocol‘s Compatible Copy-free Serialization + In order to support copy-free serialization better and more efficiently, "Cap 'n Proto" uses a self-developed codec format, but it is difficult to be implemented in the current environment where "Thrift" and "ProtoBuf" are dominant. In order to achieve the performance of copy-free serialization with protocol compatibility, we started the exploration of copy-free serialization that is compatible with "Thrift" protocol. "Cap 'n Proto" is a benchmark for copy-free serialization, so let's see if the optimizations on "Cap 'n Proto" can be applied to Thrift: + - Nature is the core of copy-free serialization, which does not use Go structure as intermediate carriers to reduce one copy. This optimization is not about a particular protocol and can be applied to any existing protocol (So it's naturally compatible with the Thrift protocol), but the user experience of "Cap 'n Proto" reflects that it needs to be carefully polished. - "Cap 'n Proto" is operated on a contiguous memory. The read & write of the encoded data can be completed at once. "Cap 'n Proto" can operate on contiguous memory because there is a pointer mechanism that allows data to be stored anywhere, allowing fields to be written in any order without affecting decoding. However, it is very likely to leave a hole in the resize due to misoperation on contiguous memory. Besides, "Thrift" has no pointer alike mechanism, so it has stricter requirements on data layout. Here are two ways to approach such problems: - Insist on operating in contiguous memory, while imposing strict regulations on users' usage: 1. Resize operation must rebuild the data structure; 2. When a structure is nested, there are strict requirements on the order in which the fields are written (we can think of it as unfolding a nested structure from the outside in, and being written in the same order) . In addition, due to TLV encoding such as Binary, when writing begins for each nesting, it requires declaration (such as "StartWriteFieldX"). - Operating not entirely in contiguous memory, alterable fields are allocated a separate piece of memory. Since memory is not completely contiguous, the write operation can't complete the output at once. In order to get closer to the performance of writing data at once, we adopted a linked buffer scheme. On the one hand, when the variable field resize occurs, only one node of the linked buffer is replaced, and there is no need to reconstruct the structure like "Cap 'n Proto”. On the other hand, there is no need to clarify the actual structure like "Thrift" when the output is needed, just write the buffer on the link. - + To summarize what we have determined previously: 1. Do not use Go structure as the intermediate carrier, directly operate the underlying memory through the interface, and complete the codec at the same time of "Get/Set". 2. Data is stored through a linked buffer. Then let's take a look at the remaining issues: + - Degradation of the user experience caused by not using Go structures. - Solution: Improve the user experience of "Get/Set" interface and make it as easy to use as the Go structure. - Binary Format of "Cap 'n Proto" is designed specifically for copy-free serialization scenarios, and although decoding is performed once for every Get, the decoding costs are minimal. The "Thrift" protocol (taking "Binary" as an example) has no mechanism that is similar to pointer. When there are multiple fields of variable size or nesting, they must be resolved sequentially instead of directly calculating the offset to get the field data location. Moreover, the cost of sequential resolution for each Get is too high. - - Solution: In addition to recording the structure's buffer nodes, we also add an index that records the pointer to the buffer node at the beginning of each field with unfixed size. The following is the ultimate performance comparison test between the current copy-free serialization scheme and "FastRead/Write" under the condition of 4 cores: - -|Package Size|Type|QPS|TP90|TP99|TP999|CPU| -|:----|:----|:----|:----|:----|:----|:----| -|1KB|Non-serialization|70,700|1 ms|3 ms|6 ms|/| -| |FastWrite/FastRead|82,490|1 ms|2 ms|4 ms|/| -|2KB|Non-serialization|65,000|1 ms|4 ms|9 ms|/| -| |FastWrite/FastRead|72,000|1 ms|2 ms|8 ms|/| -|4KB|Non-serialization|56,400|2 ms|5 ms|10 ms|380%| -| |FastWrite/FastRead|52,700|2 ms|4 ms|10 ms|380%| -|32KB|Non-serialization|27,400|/|/|/|/| -| |FastWrite/FastRead|19,500|/|/|/|/| -|1MB|Non-serialization|986|53 ms|56 ms|59 ms|260%| -| |FastWrite/FastRead|942|55 ms|59 ms|62 ms|290%| -|10MB|Non-serialization|82|630 ms|640 ms|645 ms|240%| -| |FastWrite/FastRead|82|630 ms|640 ms|640 ms|270 + - Solution: In addition to recording the structure's buffer nodes, we also add an index that records the pointer to the buffer node at the beginning of each field with unfixed size. The following is the ultimate performance comparison test between the current copy-free serialization scheme and "FastRead/Write" under the condition of 4 cores: + +| Package Size | Type | QPS | TP90 | TP99 | TP999 | CPU | +| :----------- | :----------------- | :----- | :----- | :----- | :----- | :--- | +| 1KB | Non-serialization | 70,700 | 1 ms | 3 ms | 6 ms | / | +| | FastWrite/FastRead | 82,490 | 1 ms | 2 ms | 4 ms | / | +| 2KB | Non-serialization | 65,000 | 1 ms | 4 ms | 9 ms | / | +| | FastWrite/FastRead | 72,000 | 1 ms | 2 ms | 8 ms | / | +| 4KB | Non-serialization | 56,400 | 2 ms | 5 ms | 10 ms | 380% | +| | FastWrite/FastRead | 52,700 | 2 ms | 4 ms | 10 ms | 380% | +| 32KB | Non-serialization | 27,400 | / | / | / | / | +| | FastWrite/FastRead | 19,500 | / | / | / | / | +| 1MB | Non-serialization | 986 | 53 ms | 56 ms | 59 ms | 260% | +| | FastWrite/FastRead | 942 | 55 ms | 59 ms | 62 ms | 290% | +| 10MB | Non-serialization | 82 | 630 ms | 640 ms | 645 ms | 240% | +| | FastWrite/FastRead | 82 | 630 ms | 640 ms | 640 ms | 270 | Summary of the test results: + - In small data package scenario, performance of non-serialization is poorer - about 85% of FastWrite/FastRead's performance. -- In large data package scenario, the performance of non-serialization is better. When processing packages larger than 4K, the performance of non-serialization is 7%-40% better compared with "FastWrite/FastRead". +- In large data package scenario, the performance of non-serialization is better. When processing packages larger than 4K, the performance of non-serialization is 7%-40% better compared with "FastWrite/FastRead". ## Postscript -Hope the above sharing can be helpful to the community. At the same time, we are trying to share memory-based IPC, io_uring, TCP zero copy, RDMA, etc., to better improve Kitex performance. And we will also focus on improving the communication scenarios of the same device and container. Welcome to join us and contribute to Go ecology together! + +Hope the above sharing can be helpful to the community. At the same time, we are trying to share memory-based IPC, io_uring, TCP zero copy, RDMA, etc., to better improve Kitex performance. And we will also focus on improving the communication scenarios of the same device and container. Welcome to join us and contribute to Go ecology together! ## Reference + - https://github.com/alecthomas/go_serialization_benchmarks - https://capnproto.org/ - [Intel C++ Compiler Classic Developer Guide and Reference](https://software.intel.com/content/www/us/en/develop/documentation/cpp-compiler-developer-guide-and-reference/top/compiler-reference/intrinsics/intrinsics-for-intel-advanced-vector-extensions-2/intrinsics-for-shuffle-operations-1/mm256-shuffle-epi8.html) diff --git a/content/en/blog/news/Kitex_performance_testing/index.md b/content/en/blog/news/Kitex_performance_testing/index.md index e1a4515819..a54842922f 100644 --- a/content/en/blog/news/Kitex_performance_testing/index.md +++ b/content/en/blog/news/Kitex_performance_testing/index.md @@ -24,19 +24,19 @@ Users can also refer to the official stress test project -- [kitex-benchmark](ht Kitex was born in ByteDance's large-scale microservices architecture practice. The scenario it is aimed at is naturally a microservices scenario. Therefore, the following will first introduce the characteristics of microservices, so that developers can understand Kitex's design thinking in depth. -* **RPC Communication Model** +- **RPC Communication Model** The communication between microservices is usually based on PingPong model. So, in addition to the conventional throughput performance index, developers also need to consider the average latency of each RPC. -* **Complex Call Chain** +- **Complex Call Chain** -An RPC call often requires multiple microservices to collaborate, and downstream services have their own dependencies, so the entire call chain will be a complex network structure. +An RPC call often requires multiple microservices to collaborate, and downstream services have their own dependencies, so the entire call chain will be a complex network structure. In this kind of complex call chains, the latency fluctuation of one intermediate node may be transmitted to the entire chain,resulting in an overall timeout. When there are many nodes on the chain, even if the fluctuation probability of each node is very low, the timeout probability that eventually converges on the chain will be magnified. Therefore, the latency fluctuation of a single service, notably P99, is also a key indicator that has a significant impact on online services. -* **Size of Data Package** +- **Size of Data Package** Although the size of transmitted data packages depends on the actual business scenario, the internal statistics of ByteDance found that most online requests are small packages (<2KB). So we focused on optimizing the performance in the small data package scenarios while taking the large package scenarios into account. @@ -58,6 +58,7 @@ Thus, the test result will not have practical value for online services. ### Alignment of Connection Model Conventional RPCs have three major connection models: + - **Short connection**: Each request creates a new connection and closes the connection immediately after the return is received. - **Persistent connection pool**: A single connection can process only one complete request & return at once. - **Connection multiplexing**: A single connection can process multiple requests & returns asynchronously at the same time. @@ -100,10 +101,12 @@ The stress test source code can be found in [kitex-benchmark](https://github.com When Server is fully loaded, P99 Latency of Kitex in connection pool mode is the lowest of all frameworks. In multiplexing mode, Kitex also performs well in each indicator. **Configuration** + - Client 16 CPUs,Server 4 CPUs - 1KB Request Package Size, Echo Scenario **Reference Data** + - KITEX: Connection Pool Model (Default Setting) - KITEX-MUX: Connection Multiplexing - Connection Multiplexing for all other Frameworks diff --git a/content/en/blog/news/Mastering_Golang_Microservices_A_Practical_Guide_Embrace_High_Performance_with_Kitex_and_Hertz/index.md b/content/en/blog/news/Mastering_Golang_Microservices_A_Practical_Guide_Embrace_High_Performance_with_Kitex_and_Hertz/index.md index c67c2424d7..57c025448f 100644 --- a/content/en/blog/news/Mastering_Golang_Microservices_A_Practical_Guide_Embrace_High_Performance_with_Kitex_and_Hertz/index.md +++ b/content/en/blog/news/Mastering_Golang_Microservices_A_Practical_Guide_Embrace_High_Performance_with_Kitex_and_Hertz/index.md @@ -3,9 +3,27 @@ date: 2024-01-10 title: "Mastering Golang Microservices - A Practical Guide: Embrace High-Performance with Kitex and Hertz" projects: ["CloudWeGo"] linkTitle: "Mastering Golang Microservices - A Practical Guide: Embrace High-Performance with Kitex and Hertz" -keywords: ["CloudWeGo", "middleware", "Kitex", "microservice framework", "ByteDance Open Source", "ByteDance","open source", "cloud native", "open source", "kubernetes", "gRPC", "microservices", "rpc", "GO", "Golang", "thrift"] +keywords: + [ + "CloudWeGo", + "middleware", + "Kitex", + "microservice framework", + "ByteDance Open Source", + "ByteDance", + "open source", + "cloud native", + "open source", + "kubernetes", + "gRPC", + "microservices", + "rpc", + "GO", + "Golang", + "thrift", + ] description: "Learn how to set up, manage, and optimize Golang microservices efficiently with this guide. It offers practical insights into the usage of Kitex and Hertz, two beginner-friendly, high-performance components of the CloudWeGo project." -author: Yacine Si Tayeb, Guangming Luo +author: Yacine Si Tayeb, Guangming Luo --- ![Image](/img/blog/Mastering_Golang_Microservices_A_Practical_Guide_Embrace_High_Performance_with_Kitex_and_Hertz/1.jpeg) @@ -30,12 +48,14 @@ As key components of CloudWeGo, Kitex & Hertz, are crucial to getting started. E Installing the CLI tool requires confirmation that the `GOPATH` environment variable is correctly defined and accessible. This is followed by installing Kitex, Thriftgo, and Hertz. The correct setup can be verified by running their respective versions. If you encounter any problems, your troubleshooting should involve a check on the setup of the Golang development environment. ### Kitex & Hertz + #### Prerequisites -Before diving into CloudWeGo development with Kitex & Hertz, make sure you have set up the Golang development environment. Please follow the Install Go guide if you haven't already. -We highly recommend using the latest version of Golang, ensuring compatibility with three most recent minor release versions (currently >= v1.16). +Before diving into CloudWeGo development with Kitex & Hertz, make sure you have set up the Golang development environment. Please follow the Install Go guide if you haven't already. + +We highly recommend using the latest version of Golang, ensuring compatibility with three most recent minor release versions (currently >= v1.16). -Additionally, make sure that `GO111MODULE` is set to `ON`. +Additionally, make sure that `GO111MODULE` is set to `ON`. ### Install the CLI tool @@ -54,38 +74,46 @@ thriftgo x.x.x $ hz --version vx.x.x ``` + **Note:** If you encounter any issues during the installation, it's likely due to gaps in the setup of the Golang development environment. Usually, you can quickly find a solution by searching for the error message online. ## III. Creating A Sample Project + ### Kitex + #### Get the example 1. You can simply click [here](https://github.com/cloudwego/kitex-examples/archive/refs/heads/main.zip) to download the example. 2. Or you can clone the sample repository `git clone https://github.com/cloudwego/kitex-examples.git`. #### Run the example + ##### Run with go + 1. Change to the `hello` directory. Hello is a simple example of Kitex using the Thrift protocol. -`cd kitex-examples/hello` + `cd kitex-examples/hello` 2. Run server -`go run .` + `go run .` 3. Run client -open another terminal and `go run ./client.` + open another terminal and `go run ./client.` ##### Run with Docker + 1. Go to the examples directory -`cd kitex-examples` + `cd kitex-examples` 2. Build the example project -`docker build -t kitex-examples`. + `docker build -t kitex-examples`. 3. Run the server -`docker run --network host kitex-examples ./hello-server` + `docker run --network host kitex-examples ./hello-server` 4. Run the client -Open another terminal and run `docker run --network host kitex-examples ./hello-client` + Open another terminal and run `docker run --network host kitex-examples ./hello-client` Congratulations! You now have successfully used Kitex to complete an RPC. ### Hertz + ##### Quick Start + To create a sample project with Hertz, start by creating the `hertz_demo` folder in the current directory and navigate to that directory. Then, create the `main.go` file and add the following code: package main @@ -118,14 +146,12 @@ To run the sample code, simply type `go run hertz_demo`. If the server is launch 2022/05/17 21:47:09.629874 transport.go:84: [Info] HERTZ: HTTP server listening on address=[::]:8888 ``` - You can test the interface by typing `curl http://127.0.0.1:8888/ping`. If everything is working correctly, you should see the following output: ```bash {"message":"pong"} ``` - ##### Using CLI tool hz You can also use the Hertz CLI tool to generate a sample project outside of the `GOPATH`. Procedures include creating an IDL file named `hello.thrift`, generating the sample code, obtaining the dependencies, and subsequently running the sample code. @@ -135,7 +161,7 @@ Assuming you are working on a folder outside of `GOPATH`, create an IDL file cal namespace go hello.world service HelloService { - string Hello(1: string name); + string Hello(1: string name); } ``` @@ -155,6 +181,7 @@ While dealing with Kitex errors, the `IsKitexError` method in the kerrors packag The Kitex framework automatically recovers all panics except those occurring within the goroutine created by the business code using the `go` keyword. ### Kitex + #### Exception Instruction Check for Kitex errors using `kerrors.IsKitexError(kerrors.ErrInternalException)`. You can check for a specified error type using `errors.Is(err, kerrors.ErrNoResolver)`. Also, note that you can use `IsTimeoutError` in kerrors to check whether it's a timeout error. @@ -194,6 +221,7 @@ if stats := ri.Stats(); stats != nil { ``` #### FAQ & Answers + **Q1: `Not enough arguments` problem when installing the code generation tool** Please try: @@ -218,6 +246,7 @@ Kitex is based on Apache Thrift v0.13 and cannot be directly upgraded since ther We recommend against using `-u` parameters during upgrades. You can run the following command to fix the version: `go mod edit -replace github.com/apache/thrift=github.com/apache/thrift@v0.13.0` ### Hertz + #### Error Type & Error Chain To handle errors more effectively, Hertz has predefined several error types: @@ -264,7 +293,7 @@ type HandlerFunc func(c context.Context, ctx *app.RequestContext) #### Metadata Storage -Both contexts (c and ctx) have the ability to store values. The choice of which one to use depends on the life cycle of the stored value and the selected context should match. The `ctx` is primarily used to store request-level variables, which are recycled after the request ends. +Both contexts (c and ctx) have the ability to store values. The choice of which one to use depends on the life cycle of the stored value and the selected context should match. The `ctx` is primarily used to store request-level variables, which are recycled after the request ends. It is characterized by high query efficiency (the bottom is map), unsafe coroutines and doesn't implement the `context.Context` Interface. The `c` is passed as the context between middleware/handler. It has all the semantics of context.Content, is safe for coroutines, and all that requires the `context.Content` interface as input arguments can just pass `c` directly. @@ -275,42 +304,57 @@ Monitoring your application is critical. Both Kitex and Hertz provide a Tracer i **Note:** As a framework, it runs with business services. Once the code of services is built, it can be deployed at virtual machines, bare metal machines, or Docker containers as it should be. ### Kitex + #### Configuration and options + For more details, please check [server option](/zh/docs/kitex/tutorials/options/server_options/), [client option](/zh/docs/kitex/tutorials/options/client_options/), and [call option](/zh/docs/kitex/tutorials/options/call_options/). ##### Observability + ###### Instrumentation Control + Kitex supports flexible enabling of basic and fine-grained Instrumentation. This includes a stats level, client tracing stats level control, server tracing stats level control, and more. For more details, please refer to the [Kitex User Guide](/docs/kitex/tutorials/observability/). ##### Logging + Kitex supports default logger implementation, injection of custom loggers, and redirection of default logger output. For more details, instructions, and examples, please refer to the [Kitex User Guide](/docs/kitex/tutorials/observability/). ##### Tracing + Kitex’s OpenTelemetry extension provides support for tracing. For more details, instructions, and examples, please refer to the [Kitex User Guide](/docs/kitex/tutorials/observability/). ##### Monitoring + The framework doesn’t provide any monitoring, but it provides a Tracer interface. This interface can be implemented by yourself and be injected via WithTracer Option. For more details, instructions, and examples, please refer to the [Kitex User Guide](/docs/kitex/tutorials/observability/). ### Hertz + #### Configuration and options + For more details, please check the [configuration instructions](/docs/hertz/reference/config/). ##### Observability + ###### Instrumentation + Hertz supports flexible enabling of basic and fine-grained Instrumentation. This includes a stats level, stats level control, and more. For more details, please refer to the [Hertz User Guide](/docs/hertz/tutorials/observability/). ##### Log + Hertz provides a default way to print logs in the standard output. It also provides several global functions, such as `hlog.Info`, `hlog.Errorf`, `hlog.CtxTracef`, and more, which are implemented in `pkg/common/hlog`, to call the corresponding methods of the default logger. For more details, instructions, and examples, please refer to the [Hertz User Guide](/docs/hertz/tutorials/observability/). ##### Tracing + In microservices, link tracing is a very important capability, which plays an important role in quickly locating problems, analyzing business bottlenecks, and restoring the link status of a request. Hertz provides the capability of link tracking and also supports user-defined link tracking. For more details, instructions, and examples, please refer to the [Hertz User Guide](/docs/hertz/tutorials/observability/). ##### Monitoring + The framework doesn’t provide any monitoring, but it provides a Tracer interface. This interface can be implemented by yourself and be injected via WithTracer Option. For more details, instructions, and examples, please refer to the [Hertz User Guide](/docs/hertz/tutorials/observability/). ## VI. Best Practices for Developing with CloudWeGo -For a real-world application of Kitex and Hertz, you can explore projects like [Bookinfo](https://github.com/cloudwego/biz-demo/tree/main/bookinfo), [Easy Note](https://github.com/cloudwego/biz-demo/tree/main/easy_note), and [Book Shop](https://github.com/cloudwego/biz-demo/tree/main/book-shop). Each of these scenarios demonstrate different business scenarios and use-cases for various CloudWeGo subprojects. + +For a real-world application of Kitex and Hertz, you can explore projects like [Bookinfo](https://github.com/cloudwego/biz-demo/tree/main/bookinfo), [Easy Note](https://github.com/cloudwego/biz-demo/tree/main/easy_note), and [Book Shop](https://github.com/cloudwego/biz-demo/tree/main/book-shop). Each of these scenarios demonstrate different business scenarios and use-cases for various CloudWeGo subprojects. Whether you're dealing with merchant or consumer management, notes maintenance, or integrating different middleware, these projects provide valuable insights into the powerful capabilities of Kitex and Hertz in different contexts. diff --git a/content/en/blog/news/The_Role_of_CloudWeGo_in_Modern_Cloud_Native_Applications/index.md b/content/en/blog/news/The_Role_of_CloudWeGo_in_Modern_Cloud_Native_Applications/index.md index a22459aa21..5a7152f0c1 100644 --- a/content/en/blog/news/The_Role_of_CloudWeGo_in_Modern_Cloud_Native_Applications/index.md +++ b/content/en/blog/news/The_Role_of_CloudWeGo_in_Modern_Cloud_Native_Applications/index.md @@ -3,19 +3,31 @@ date: 2023-11-28 title: "The Role of CloudWeGo in Modern Cloud-Native Applications" projects: ["CloudWeGo"] linkTitle: "The Role of CloudWeGo in Modern Cloud-Native Applications" -keywords: ["CloudWeGo", "middleware", "Kitex", "microservice framework", "ByteDance Open Source", "open source", "cloud native", "open source", "kubernetes", "gRPC", "microservices"] +keywords: + [ + "CloudWeGo", + "middleware", + "Kitex", + "microservice framework", + "ByteDance Open Source", + "open source", + "cloud native", + "open source", + "kubernetes", + "gRPC", + "microservices", + ] description: "Explore CloudWeGo, ByteDance's robust set of microservices middleware, in this detailed look at its role in the modernization of IT infrastructure. Discover CloudWeGo's versatility in facilitating cloud-native applications, its unique advantages, and its impact across various industries." -author: Yacine Si Tayeb, Guangming Luo +author: Yacine Si Tayeb, Guangming Luo --- - ![Image](/img/blog/The_Role_of_CloudWeGo_in_Modern_Cloud_Native_Applications/1.png) # I. Introduction In the current era of infrastructure modernization, the term "Cloud-Native Applications" has emerged as a significant factor driving the evolution of the IT landscape. These applications inherently embody the concept of flexibility, scalability, and high availability and are built and delivered in a rapid, dynamic manner. They leverage modern application development frameworks and methodologies like microservices, containerization, and DevOps. Amidst the vast array of technologies accelerating the development and deployment of cloud-native applications is CloudWeGo, a notable player offering a distinctive edge to developers and organizations. -[CloudWeGo](https://www.cloudwego.io), a brainchild of [ByteDance](https://www.bytedance.com/en/), has established itself as a set of microservices middleware. It comprises a collection of high-performance, highly extensible, and highly reliable projects focused on microservices communication and governance. +[CloudWeGo](https://www.cloudwego.io), a brainchild of [ByteDance](https://www.bytedance.com/en/), has established itself as a set of microservices middleware. It comprises a collection of high-performance, highly extensible, and highly reliable projects focused on microservices communication and governance. In the face of the rapidly escalating hybrid and cloud-native microservices environment, CloudWeGo has proved to be a powerful fine-tuned tool to cater to the explicit requirements of such architectures. This article will explore the critical role CloudWeGo plays in understanding, architecting, and leveraging modern cloud-native applications. In the following sections, we will delve deeper into what exactly CloudWeGo is, its role in facilitating robust cloud-native applications, its specific advantages, and successfully implemented practical use-cases. Our objective is to present a well-rounded view of CloudWeGo's impact and potential in revolutionizing the way cloud-native applications are structured and operated. @@ -38,7 +50,7 @@ With CloudWeGo, developers enjoy the flexibility of constructing and seamlessly Whether you're a seasoned veteran or a beginner developer just starting in the world of microservices, CloudWeGo simplifies the journey, making the complex and challenging world of hybrid microservices a little less daunting and a lot more exciting. -# III. Role of CloudWeGo in Cloud-Native Applications +# III. Role of CloudWeGo in Cloud-Native Applications In our fast-paced digital world, cloud-native applications are revolutionizing how businesses function. By leveraging cloud computing capabilities, these applications aim to enhance scalability, flexibility, and resilience. They adhere to a diverse set of requirements and characteristics: @@ -88,7 +100,7 @@ CloudWeGo astounds with its high performance, a direct result of incorporating f ### Flexibility Through Extensibility & Interoperability -A standout feature of CloudWeGo lies in its designed extensibility, allowing users to customize its functionality to suit their individual needs. CloudWeGo employs a modular or layered framework providing a set of interfaces and default implementation options. +A standout feature of CloudWeGo lies in its designed extensibility, allowing users to customize its functionality to suit their individual needs. CloudWeGo employs a modular or layered framework providing a set of interfaces and default implementation options. The layered design, evident in Kitex and Hertz, allows developers to infuse their implementations into the framework, customizing it for specific needs. This extensibility enables them to replace or enhance default implementations, adapting CloudWeGo to distinct use cases or seamless integration with other libraries and tools. @@ -104,7 +116,7 @@ CloudWeGo is designed for flexibility, managing to cater to a vast range of appl CloudWeGo offers a plethora of benefits for the gaming industry. The platform stands synonymous with increased scalability, optimized performance, and simplified business logic, made possible due to its resource-efficient components like rate limiting, monitoring, and service registration/discovery. Additionally, integration with OpenTelemetry offers valuable monitoring and diagnostics capabilities for developers to optimize game services and ensure an exceptional gaming experience. -[Tanwan Games](https://www.tanwan.com/game/), known for popular games such as [West War](https://play.google.com/store/apps/details?id=com.twon.westwar), faced substantial technical challenges around instantaneous high concurrency during game launches, game updates, extensive data pushes from partners, and interface overloads. +[Tanwan Games](https://www.tanwan.com/game/), known for popular games such as [West War](https://play.google.com/store/apps/details?id=com.twon.westwar), faced substantial technical challenges around instantaneous high concurrency during game launches, game updates, extensive data pushes from partners, and interface overloads. To overcome these challenges, they turned to CloudWeGo, employing the Hertz framework for HTTP services and the Kitex framework for RPC microservices. Additionally, they leveraged Nacos for service discovery and registration, OpenTelemetry for tracing, Prometheus for monitoring, and Kitex's built-in rate-limiting strategies for traffic shaping. The tangible benefits of embracing CloudWeGo include: @@ -130,6 +142,7 @@ The e-commerce industry faces high concurrency and performance challenges. When ![Image](/img/blog/The_Role_of_CloudWeGo_in_Modern_Cloud_Native_Applications/4.png) The benefits of integrating CloudWeGo were immediately evident: + - An improved ability to process a higher number of orders within a given timeframe. - A shorter processing time even for a specified number of orders, with this performance gap becoming increasingly pronounced as the order volume increased. - A substantial reduction in machine costs required to support the system. diff --git a/content/en/blog/news/_index.md b/content/en/blog/news/_index.md index ae5042fe4a..df9f422b2a 100644 --- a/content/en/blog/news/_index.md +++ b/content/en/blog/news/_index.md @@ -4,5 +4,3 @@ linkTitle: "News" projects: [] weight: 1 --- - - diff --git a/content/en/blog/news/bytedance_gonet_practice/index.md b/content/en/blog/news/bytedance_gonet_practice/index.md index 15eb290300..baedd69177 100644 --- a/content/en/blog/news/bytedance_gonet_practice/index.md +++ b/content/en/blog/news/bytedance_gonet_practice/index.md @@ -3,7 +3,8 @@ date: 2020-05-24 title: "ByteDance Practices on Go Network Library" projects: ["Netpoll"] linkTitle: "ByteDance Practices on Go Network Library" -keywords: ["Netpoll", "Go", "epoll", "Network Library", "Multiplexing", "ZeroCopy"] +keywords: + ["Netpoll", "Go", "epoll", "Network Library", "Multiplexing", "ZeroCopy"] description: "This blog introduces the design and practice of Bytedance self-developed network library Netpoll as well as the actual problems and solutions, hope to provide you with some reference." author: Hchen, Pure White --- diff --git a/content/en/blog/news/open_source_volo/index.md b/content/en/blog/news/open_source_volo/index.md index 907b1f3829..a6073b9cad 100644 --- a/content/en/blog/news/open_source_volo/index.md +++ b/content/en/blog/news/open_source_volo/index.md @@ -3,7 +3,15 @@ date: 2022-08-30 title: "China's First Rust-based RPC Framework - Volo is Officially Open Source!" projects: ["Volo"] linkTitle: "China's first RPC framework based on Rust language - Volo is officially open source!" -keywords: ["CloudWeGo", "RPC framework", "Volo", "Rust", "ByteDance Open Source", "open source"] +keywords: + [ + "CloudWeGo", + "RPC framework", + "Volo", + "Rust", + "ByteDance Open Source", + "open source", + ] description: "This article introduces ByteDance's official open source Rust RPC framework — Volo, and focuses on the project's origin, main features and related ecosystem." author: CloudWeGo Team --- @@ -84,4 +92,3 @@ We hope this article has provided you with a basic understanding of [Volo](https - [Volo Tutorial](/docs/volo/) - [Volo Documentation](https://docs.rs/volo) - [Volo-rs organization](https://github.com/volo-rs) - diff --git a/content/en/blog/releases/Hertz/release-v010.md b/content/en/blog/releases/Hertz/release-v010.md index ec5da28a25..5bb564d3fb 100644 --- a/content/en/blog/releases/Hertz/release-v010.md +++ b/content/en/blog/releases/Hertz/release-v010.md @@ -8,33 +8,32 @@ description: > ## Feature -* [[#31](https://github.com/cloudwego/hertz/pull/31)] feat: close connection after responding to the short-connection request. -* [[#44](https://github.com/cloudwego/hertz/pull/44)] feat: add the VisitAllCustomHeader method. -* [[#59](https://github.com/cloudwego/hertz/pull/59)] feat: support windows. -* [[#70](https://github.com/cloudwego/hertz/pull/70)] feat: add code generator hz. -* [[#64](https://github.com/cloudwego/hertz/pull/64)] feat: add adaptor for Hertz Request & Response to net/http Request & ResponseWriter. -* [[#45](https://github.com/cloudwego/hertz/pull/45)] feat: add ctx.Body(). +- [[#31](https://github.com/cloudwego/hertz/pull/31)] feat: close connection after responding to the short-connection request. +- [[#44](https://github.com/cloudwego/hertz/pull/44)] feat: add the VisitAllCustomHeader method. +- [[#59](https://github.com/cloudwego/hertz/pull/59)] feat: support windows. +- [[#70](https://github.com/cloudwego/hertz/pull/70)] feat: add code generator hz. +- [[#64](https://github.com/cloudwego/hertz/pull/64)] feat: add adaptor for Hertz Request & Response to net/http Request & ResponseWriter. +- [[#45](https://github.com/cloudwego/hertz/pull/45)] feat: add ctx.Body(). ## Optimize -* [[#57](https://github.com/cloudwego/hertz/pull/57)] optimize: use http.TimeFormat as layout for http date, which can avoid more copying. -* [[#58](https://github.com/cloudwego/hertz/pull/58)] optimize: add remote address to the error log when server processes the error. -* [[#41](https://github.com/cloudwego/hertz/pull/41)] optimize: use CtxErrorf instead of ‘Errorf’ when server panic. +- [[#57](https://github.com/cloudwego/hertz/pull/57)] optimize: use http.TimeFormat as layout for http date, which can avoid more copying. +- [[#58](https://github.com/cloudwego/hertz/pull/58)] optimize: add remote address to the error log when server processes the error. +- [[#41](https://github.com/cloudwego/hertz/pull/41)] optimize: use CtxErrorf instead of ‘Errorf’ when server panic. ## Refactor -* [[#37](https://github.com/cloudwego/hertz/pull/37)] refactor: unify the entry of setting request options to prevent options uninitialized from causing panic. -* [[#52](https://github.com/cloudwego/hertz/pull/52)] refactor: omit redundant nil check around loop. -* [[#33](https://github.com/cloudwego/hertz/pull/33)] refactor: simplify code in AddMissingPort. -* [[#27](https://github.com/cloudwego/hertz/pull/27)] refactor: use errors.NewPublic rather than fmt.Errorf. -* [[#34](https://github.com/cloudwego/hertz/pull/34)] refactor: remove fshandler and related tests. +- [[#37](https://github.com/cloudwego/hertz/pull/37)] refactor: unify the entry of setting request options to prevent options uninitialized from causing panic. +- [[#52](https://github.com/cloudwego/hertz/pull/52)] refactor: omit redundant nil check around loop. +- [[#33](https://github.com/cloudwego/hertz/pull/33)] refactor: simplify code in AddMissingPort. +- [[#27](https://github.com/cloudwego/hertz/pull/27)] refactor: use errors.NewPublic rather than fmt.Errorf. +- [[#34](https://github.com/cloudwego/hertz/pull/34)] refactor: remove fshandler and related tests. ## Style -* [[#29](https://github.com/cloudwego/hertz/pull/29)] style(*): fix typos. +- [[#29](https://github.com/cloudwego/hertz/pull/29)] style(\*): fix typos. ## Docs -* [[#60](https://github.com/cloudwego/hertz/pull/60)] docs: add icon in README.md and README_cn.md. -* [[#54](https://github.com/cloudwego/hertz/pull/54)] docs: Update README.md. - +- [[#60](https://github.com/cloudwego/hertz/pull/60)] docs: add icon in README.md and README_cn.md. +- [[#54](https://github.com/cloudwego/hertz/pull/54)] docs: Update README.md. diff --git a/content/en/blog/releases/Hertz/release-v020.md b/content/en/blog/releases/Hertz/release-v020.md index 04439afe2e..d3d609c82b 100644 --- a/content/en/blog/releases/Hertz/release-v020.md +++ b/content/en/blog/releases/Hertz/release-v020.md @@ -8,41 +8,40 @@ description: > ## Feature -* [[#124](https://github.com/cloudwego/hertz/pull/124)] feat: add option to remove hijackConnPool. -* [[#116](https://github.com/cloudwego/hertz/pull/116)] feat: update for template. -* [[#130](https://github.com/cloudwego/hertz/pull/130)] feat: add a warning log for invalid character in Cookie.Value. -* [[#143](https://github.com/cloudwego/hertz/pull/143)] feat: custom signal to graceful shutdown -* [[#114](https://github.com/cloudwego/hertz/pull/114)] feat: release buffer in standard network method. -* [[#112](https://github.com/cloudwego/hertz/pull/112)] feat: parse post args in bodystream. -* [[#105](https://github.com/cloudwego/hertz/pull/105)] feat: client abstracts hostclient layer. -* [[#92](https://github.com/cloudwego/hertz/pull/92)] feat: hz support windows. -* [[#102](https://github.com/cloudwego/hertz/pull/102)] feat: client removes default retry logic. +- [[#124](https://github.com/cloudwego/hertz/pull/124)] feat: add option to remove hijackConnPool. +- [[#116](https://github.com/cloudwego/hertz/pull/116)] feat: update for template. +- [[#130](https://github.com/cloudwego/hertz/pull/130)] feat: add a warning log for invalid character in Cookie.Value. +- [[#143](https://github.com/cloudwego/hertz/pull/143)] feat: custom signal to graceful shutdown +- [[#114](https://github.com/cloudwego/hertz/pull/114)] feat: release buffer in standard network method. +- [[#112](https://github.com/cloudwego/hertz/pull/112)] feat: parse post args in bodystream. +- [[#105](https://github.com/cloudwego/hertz/pull/105)] feat: client abstracts hostclient layer. +- [[#92](https://github.com/cloudwego/hertz/pull/92)] feat: hz support windows. +- [[#102](https://github.com/cloudwego/hertz/pull/102)] feat: client removes default retry logic. ## Optimize -* [[#111](https://github.com/cloudwego/hertz/pull/111)] optimize: pre-allocate slice when calling bytesconv.AppendHTTPDate. -* [[#128](https://github.com/cloudwego/hertz/pull/128)] optimize: remove useless judgement. -* [[#108](https://github.com/cloudwego/hertz/pull/108)] optimize: avoid parsing regular expression repeatedly. +- [[#111](https://github.com/cloudwego/hertz/pull/111)] optimize: pre-allocate slice when calling bytesconv.AppendHTTPDate. +- [[#128](https://github.com/cloudwego/hertz/pull/128)] optimize: remove useless judgement. +- [[#108](https://github.com/cloudwego/hertz/pull/108)] optimize: avoid parsing regular expression repeatedly. ## Chore -* [[#125](https://github.com/cloudwego/hertz/pull/125)] Update pr-check.yml. +- [[#125](https://github.com/cloudwego/hertz/pull/125)] Update pr-check.yml. ## Fix -* [[#104](https://github.com/cloudwego/hertz/pull/104)] fix: use defer to guarantee that mutex will be unlocked. -* [[#96](https://github.com/cloudwego/hertz/pull/96)] fix: ci exec /bin/license-eye: exec format error +- [[#104](https://github.com/cloudwego/hertz/pull/104)] fix: use defer to guarantee that mutex will be unlocked. +- [[#96](https://github.com/cloudwego/hertz/pull/96)] fix: ci exec /bin/license-eye: exec format error ## Style -* [[#103](https://github.com/cloudwego/hertz/pull/103)] style: fixed the typo "ungzipped" to "gunzipped". -* [[#90](https://github.com/cloudwego/hertz/pull/90)] style: use const var and remove duplicate type conversions. +- [[#103](https://github.com/cloudwego/hertz/pull/103)] style: fixed the typo "ungzipped" to "gunzipped". +- [[#90](https://github.com/cloudwego/hertz/pull/90)] style: use const var and remove duplicate type conversions. ## Refactor -* [[#94](https://github.com/cloudwego/hertz/pull/94)] refactor: use appendCookiePart to simplify code. +- [[#94](https://github.com/cloudwego/hertz/pull/94)] refactor: use appendCookiePart to simplify code. ## Docs -* [[#97](https://github.com/cloudwego/hertz/pull/97)] docs: use comma to separate && remove extra space. - +- [[#97](https://github.com/cloudwego/hertz/pull/97)] docs: use comma to separate && remove extra space. diff --git a/content/en/blog/releases/Hertz/release-v030.md b/content/en/blog/releases/Hertz/release-v030.md index d99cfe5309..70e1e84bcc 100644 --- a/content/en/blog/releases/Hertz/release-v030.md +++ b/content/en/blog/releases/Hertz/release-v030.md @@ -8,42 +8,41 @@ description: > ## Feature -* [[#182](https://github.com/cloudwego/hertz/pull/182)] feat: add service registration & service discovery & load balancing. -* [[#6]](https://github.com/hertz-contrib/registry/pull/6) feat: add zookeeper register. -* [[#7]](https://github.com/hertz-contrib/registry/pull/7) feat: add nacos registry. -* [[#8]](https://github.com/hertz-contrib/registry/pull/8) feat: Support Hertz to use Consul for service discovery and registration. -* [[#9]](https://github.com/hertz-contrib/registry/pull/9) feat: add polaris registry. -* [[#14]](https://github.com/hertz-contrib/registry/pull/14) feat: add etcd registry. -* [[#15]](https://github.com/hertz-contrib/registry/pull/15) feat: support servicecomb. -* [[#16]](https://github.com/hertz-contrib/registry/pull/16) feat: support service registration and discovery with Netflix Eureka. +- [[#182](https://github.com/cloudwego/hertz/pull/182)] feat: add service registration & service discovery & load balancing. +- [[#6]](https://github.com/hertz-contrib/registry/pull/6) feat: add zookeeper register. +- [[#7]](https://github.com/hertz-contrib/registry/pull/7) feat: add nacos registry. +- [[#8]](https://github.com/hertz-contrib/registry/pull/8) feat: Support Hertz to use Consul for service discovery and registration. +- [[#9]](https://github.com/hertz-contrib/registry/pull/9) feat: add polaris registry. +- [[#14]](https://github.com/hertz-contrib/registry/pull/14) feat: add etcd registry. +- [[#15]](https://github.com/hertz-contrib/registry/pull/15) feat: support servicecomb. +- [[#16]](https://github.com/hertz-contrib/registry/pull/16) feat: support service registration and discovery with Netflix Eureka. ## Refactor -* [[#175](https://github.com/cloudwego/hertz/pull/175)] refactor: distinguish between global dialer and local dialer. +- [[#175](https://github.com/cloudwego/hertz/pull/175)] refactor: distinguish between global dialer and local dialer. ## Optimize -* [[#205](https://github.com/cloudwego/hertz/pull/205)] optimize: func checkPathValid returns true if the path is valid. +- [[#205](https://github.com/cloudwego/hertz/pull/205)] optimize: func checkPathValid returns true if the path is valid. ## Test -* [[#174](https://github.com/cloudwego/hertz/pull/174)] test: correcting TestRouterMiddlewareAndStatic. +- [[#174](https://github.com/cloudwego/hertz/pull/174)] test: correcting TestRouterMiddlewareAndStatic. ## Fix -* [[#190](https://github.com/cloudwego/hertz/pull/190)] fix: modify the same middleware name. -* [[#192](https://github.com/cloudwego/hertz/pull/192)] fix: fix the problem of the same package name in handler. -* [[#208](https://github.com/cloudwego/hertz/pull/208)] fix: deregister failed when service shutdown. -* [[#202](https://github.com/cloudwego/hertz/pull/202)] fix: get wrong local loopback IPv6. -* [[#196](https://github.com/cloudwego/hertz/pull/196)] fix: typo. -* [[#155](https://github.com/cloudwego/hertz/pull/155)] fix: name_style_thrift. -* [[#169](https://github.com/cloudwego/hertz/pull/169)] fix: thrift namespace. -* [[#184](https://github.com/cloudwego/hertz/pull/184)] fix: hijack conn throw timeout err when using standard network lib. -* [[#162](https://github.com/cloudwego/hertz/pull/162)] fix: generate router register error. +- [[#190](https://github.com/cloudwego/hertz/pull/190)] fix: modify the same middleware name. +- [[#192](https://github.com/cloudwego/hertz/pull/192)] fix: fix the problem of the same package name in handler. +- [[#208](https://github.com/cloudwego/hertz/pull/208)] fix: deregister failed when service shutdown. +- [[#202](https://github.com/cloudwego/hertz/pull/202)] fix: get wrong local loopback IPv6. +- [[#196](https://github.com/cloudwego/hertz/pull/196)] fix: typo. +- [[#155](https://github.com/cloudwego/hertz/pull/155)] fix: name_style_thrift. +- [[#169](https://github.com/cloudwego/hertz/pull/169)] fix: thrift namespace. +- [[#184](https://github.com/cloudwego/hertz/pull/184)] fix: hijack conn throw timeout err when using standard network lib. +- [[#162](https://github.com/cloudwego/hertz/pull/162)] fix: generate router register error. ## Chore -* [[#189](https://github.com/cloudwego/hertz/pull/189)] Revert "fix: generate router register error". -* [[#203](https://github.com/cloudwego/hertz/pull/203)] add v6 support for AddMissingPort function. -* [[#186](https://github.com/cloudwego/hertz/pull/186)] chore: support codecov. - +- [[#189](https://github.com/cloudwego/hertz/pull/189)] Revert "fix: generate router register error". +- [[#203](https://github.com/cloudwego/hertz/pull/203)] add v6 support for AddMissingPort function. +- [[#186](https://github.com/cloudwego/hertz/pull/186)] chore: support codecov. diff --git a/content/en/blog/releases/Hertz/release-v032.md b/content/en/blog/releases/Hertz/release-v032.md index 356b42f061..954bc19cbc 100644 --- a/content/en/blog/releases/Hertz/release-v032.md +++ b/content/en/blog/releases/Hertz/release-v032.md @@ -8,23 +8,22 @@ description: > ## Feature -* [[#198](https://github.com/cloudwego/hertz/pull/198)] feat: add the function to get the client dialer name. -* [[#251](https://github.com/cloudwego/hertz/pull/251)] feat: add a startup log to display the name of the loaded network library. +- [[#198](https://github.com/cloudwego/hertz/pull/198)] feat: add the function to get the client dialer name. +- [[#251](https://github.com/cloudwego/hertz/pull/251)] feat: add a startup log to display the name of the loaded network library. ## Refactor -* [[#238](https://github.com/cloudwego/hertz/pull/238)] refactor: refactor the client logic initialize for HostClient and TLSHostClient. +- [[#238](https://github.com/cloudwego/hertz/pull/238)] refactor: refactor the client logic initialize for HostClient and TLSHostClient. ## Optimize -* [[#226](https://github.com/cloudwego/hertz/pull/226)] optimize: add a warning log for illegal status code. +- [[#226](https://github.com/cloudwego/hertz/pull/226)] optimize: add a warning log for illegal status code. ## Fix -* [[#249](https://github.com/cloudwego/hertz/pull/249)] fix: add channel signal judge to allow onShutdownHook to complete or timeout. -* [[#232](https://github.com/cloudwego/hertz/pull/232)] fix: fix some trailing slash redirect bugs. +- [[#249](https://github.com/cloudwego/hertz/pull/249)] fix: add channel signal judge to allow onShutdownHook to complete or timeout. +- [[#232](https://github.com/cloudwego/hertz/pull/232)] fix: fix some trailing slash redirect bugs. ## Chore -* [[#217](https://github.com/cloudwego/hertz/pull/217)] chore: update pr template. - +- [[#217](https://github.com/cloudwego/hertz/pull/217)] chore: update pr template. diff --git a/content/en/blog/releases/Hertz/release-v040.md b/content/en/blog/releases/Hertz/release-v040.md index e0f915a497..573b4a8234 100644 --- a/content/en/blog/releases/Hertz/release-v040.md +++ b/content/en/blog/releases/Hertz/release-v040.md @@ -8,46 +8,45 @@ description: > ## Feature -* [[#289](https://github.com/cloudwego/hertz/pull/289)] feat: render support IndentedJSON. -* [[#304](https://github.com/cloudwego/hertz/pull/304)] feat: support errors format for the recovery middleware. -* [[#278](https://github.com/cloudwego/hertz/pull/278)] feat: add compile tag for json implementation. -* [[#239](https://github.com/cloudwego/hertz/pull/239)] feat: add retry extension for client. -* [[#265](https://github.com/cloudwego/hertz/pull/265)] feat: add closeNoResetBuffer method for standard network. -* [[#258](https://github.com/cloudwego/hertz/pull/258)] feat: errors support format. +- [[#289](https://github.com/cloudwego/hertz/pull/289)] feat: render support IndentedJSON. +- [[#304](https://github.com/cloudwego/hertz/pull/304)] feat: support errors format for the recovery middleware. +- [[#278](https://github.com/cloudwego/hertz/pull/278)] feat: add compile tag for json implementation. +- [[#239](https://github.com/cloudwego/hertz/pull/239)] feat: add retry extension for client. +- [[#265](https://github.com/cloudwego/hertz/pull/265)] feat: add closeNoResetBuffer method for standard network. +- [[#258](https://github.com/cloudwego/hertz/pull/258)] feat: errors support format. ## Optimize -* [[#295](https://github.com/cloudwego/hertz/pull/295)] optimize: ignore flushing error when connection is closed or reset. -* [[#322](https://github.com/cloudwego/hertz/pull/322)] optimize: modify the default log of the recovery middleware. -* [[#266](https://github.com/cloudwego/hertz/pull/266)] optimize(hlog): distinguish systemlogger and defaultlogger. -* [[#280](https://github.com/cloudwego/hertz/pull/280)] optimize: add listening log when using standard lib. +- [[#295](https://github.com/cloudwego/hertz/pull/295)] optimize: ignore flushing error when connection is closed or reset. +- [[#322](https://github.com/cloudwego/hertz/pull/322)] optimize: modify the default log of the recovery middleware. +- [[#266](https://github.com/cloudwego/hertz/pull/266)] optimize(hlog): distinguish systemlogger and defaultlogger. +- [[#280](https://github.com/cloudwego/hertz/pull/280)] optimize: add listening log when using standard lib. ## Refactor -* [[#318](https://github.com/cloudwego/hertz/pull/318)] refactor: add SetRetryIf to remain compatible. +- [[#318](https://github.com/cloudwego/hertz/pull/318)] refactor: add SetRetryIf to remain compatible. ## Test -* [[#299](https://github.com/cloudwego/hertz/pull/299)] test: enrich ut for pkg/protocol/header.go. -* [[#290](https://github.com/cloudwego/hertz/pull/290)] test: enrich ut for pkg/app/server/option.go. -* [[#274](https://github.com/cloudwego/hertz/pull/274)] test: increase internal/bytesconv unit test statement coverage. -* [[#285](https://github.com/cloudwego/hertz/pull/285)] test: enrich unit tests for pkg/protocol/request.go. -* [[#271](https://github.com/cloudwego/hertz/pull/271)] test: ut supplementary for pkg/network. -* [[#264](https://github.com/cloudwego/hertz/pull/264)] test: add ut for hertz/pkg/common/adaptor. -* [[#267](https://github.com/cloudwego/hertz/pull/267)] test(pkg/common/config): pkg/common/config test coverage. +- [[#299](https://github.com/cloudwego/hertz/pull/299)] test: enrich ut for pkg/protocol/header.go. +- [[#290](https://github.com/cloudwego/hertz/pull/290)] test: enrich ut for pkg/app/server/option.go. +- [[#274](https://github.com/cloudwego/hertz/pull/274)] test: increase internal/bytesconv unit test statement coverage. +- [[#285](https://github.com/cloudwego/hertz/pull/285)] test: enrich unit tests for pkg/protocol/request.go. +- [[#271](https://github.com/cloudwego/hertz/pull/271)] test: ut supplementary for pkg/network. +- [[#264](https://github.com/cloudwego/hertz/pull/264)] test: add ut for hertz/pkg/common/adaptor. +- [[#267](https://github.com/cloudwego/hertz/pull/267)] test(pkg/common/config): pkg/common/config test coverage. ## Docs -* [[#328](https://github.com/cloudwego/hertz/pull/328)] docs: add lark extension to readme.md. -* [[#325](https://github.com/cloudwego/hertz/pull/325)] docs: update performance data in README and README_cn. -* [[#307](https://github.com/cloudwego/hertz/pull/307)] docs(README): add hertz extensions list. +- [[#328](https://github.com/cloudwego/hertz/pull/328)] docs: add lark extension to readme.md. +- [[#325](https://github.com/cloudwego/hertz/pull/325)] docs: update performance data in README and README_cn. +- [[#307](https://github.com/cloudwego/hertz/pull/307)] docs(README): add hertz extensions list. ## Style -* [[#316](https://github.com/cloudwego/hertz/pull/316)] style: remove empty comments for license. +- [[#316](https://github.com/cloudwego/hertz/pull/316)] style: remove empty comments for license. ## Chore -* [[#272](https://github.com/cloudwego/hertz/pull/272)] chore: upgrade sonic version. -* [[#310](https://github.com/cloudwego/hertz/pull/310)] chore: change license header style to avoid format error of buildtag from CI check. - +- [[#272](https://github.com/cloudwego/hertz/pull/272)] chore: upgrade sonic version. +- [[#310](https://github.com/cloudwego/hertz/pull/310)] chore: change license header style to avoid format error of buildtag from CI check. diff --git a/content/en/blog/releases/Hertz/release-v050.md b/content/en/blog/releases/Hertz/release-v050.md index afc859de05..7fdc461776 100644 --- a/content/en/blog/releases/Hertz/release-v050.md +++ b/content/en/blog/releases/Hertz/release-v050.md @@ -48,6 +48,7 @@ Instructions: > For details, see: https://github.com/cloudwego/hertz-examples/tree/main/hz_client 1. Define the IDL + ```go namespace go toutiao.middleware.hzClient struct QueryReq { @@ -62,16 +63,19 @@ service Hertz121 { api.base_domain="http://127.0.0.1:8888"; ) ``` + 2. Generate code Based on the above IDL, the server and client codes can be generated separately: Server: + ```go hz new --idl=psm.thrift --handler_by_method -t=template=slim ``` Client: + ```go hz client --idl=psm.thrift --model_dir=hertz_gen -t=template=slim --client_dir=hz_client ``` @@ -81,5 +85,6 @@ hz client --idl=psm.thrift --model_dir=hertz_gen -t=template=slim --client_dir=h ## Full Release Note The complete Release Note can refer to: -* Hertz: https://github.com/cloudwego/hertz/releases/tag/v0.5.0 -* Hz(scaffolding): https://github.com/cloudwego/hertz/releases/tag/cmd%2Fhz%2Fv0.5.0 + +- Hertz: https://github.com/cloudwego/hertz/releases/tag/v0.5.0 +- Hz(scaffolding): https://github.com/cloudwego/hertz/releases/tag/cmd%2Fhz%2Fv0.5.0 diff --git a/content/en/blog/releases/Hertz/release-v060.md b/content/en/blog/releases/Hertz/release-v060.md index 4423c97d04..1d3cfbaeca 100644 --- a/content/en/blog/releases/Hertz/release-v060.md +++ b/content/en/blog/releases/Hertz/release-v060.md @@ -9,10 +9,13 @@ description: > In version 0.6.0 of Hertz, in addition to regular iterative optimization, we also brought several important features. ## HTTP Trailer support + In Hertz v0.6.0, we support encoding and parsing of HTTP Trailer. ->https://github.com/cloudwego/hertz-examples/tree/main/trailer -* Write Trailer +> https://github.com/cloudwego/hertz-examples/tree/main/trailer + +- Write Trailer + ```go // server func handler(c context.Context, ctx *app.RequestContext){ @@ -22,7 +25,9 @@ func handler(c context.Context, ctx *app.RequestContext){ // client req.Header.Trailer().Set("Hertz", "Good") ``` -* Read Trailer + +- Read Trailer + ```go // server func handler(c context.Context, ctx *app.RequestContext){ @@ -34,28 +39,37 @@ resp.Header.Trailer().Get("Hertz") ``` ## HTTP/1.1 supports for Response Writer hijacking + In Hertz v0.6.0, we extended the HTTP/1.1 write request approach. Based on the original write request flow, we support users to hijack the Response Writer in the business handler/middleware to achieve a more flexible write request approach.
In simple terms, all the original "underlying write" logic is unified behind the handler/middleware return, which has two obvious limitations. + 1. The user has no control over the timing of the request flush to the other end 2. For the scenario of incremental data generation & real-time writing to the peer by chunk, the usage is relatively complicated and restrictive on top of the old architecture Based on this, we extend a Writer that provides the ability to flush request headers and request bodies on its own, while providing support for users to send chunk data on demand. See https://github.com/cloudwego/hertz/pull/610 for a detailed implementation. + ### Major Changes + 1. Added an interface definition that extends Writer, `Writers` that implement this interface can be used to hijack Response Writer: - ```go - type ExtWriter interface { - io.Writer - Flush() error - - // Finalize will be called by framework before the writer is released. - // Implementations must guarantee that Finalize is safe for multiple calls. - Finalize() error - } - ``` + + ```go + type ExtWriter interface { + io.Writer + Flush() error + + // Finalize will be called by framework before the writer is released. + // Implementations must guarantee that Finalize is safe for multiple calls. + Finalize() error + } + ``` + 2. Provides a `Chunk Writer` that implements the above interface (you can refer to this for similar requirements): `chunkedBodyWrite` 3. HTTP/1.1 does the corresponding processing (skipping the default write request logic) for Response write operations where the Writer has been hijacked, and finally calls the `Finalize()` method of the `ExtWriter` interface to complete a request write back + ### Usage + As above, Hertz provides a default `ExtWriter` implementation to meet the user's active flush needs in the handler/middleware, and it is very simple to use. + ```go h.GET("/flush/chunk", func(c context.Context, ctx *app.RequestContext) { // Hijack the writer of response @@ -72,21 +86,25 @@ h.GET("/flush/chunk", func(c context.Context, ctx *app.RequestContext) { ## Scaffolding Tool Usage Optimization & Best Practices In hz v0.6.0, we have made a number of optimizations to the organization of the generated code, allowing for a more flexible code organization + ### Major Optimization -* The `new` command supports the "router_dir" option and works with the existing "handler_dir" and "model_dir" to fully customize the path to the IDL generation product; it also persists these custom options in the ".hz" file, which can be read automatically during `update`, reducing the complexity of the command -* Add the ability to search up the "go.mod" file so that hertz can share the same "go module" with other projects when it is a subproject -* Add the ability to reference third-party IDL products in the "handler", so that IDL products can be maintained separately in the third-party repository and not stored in the project directory, further enhancing IDL management capabilities + +- The `new` command supports the "router_dir" option and works with the existing "handler_dir" and "model_dir" to fully customize the path to the IDL generation product; it also persists these custom options in the ".hz" file, which can be read automatically during `update`, reducing the complexity of the command +- Add the ability to search up the "go.mod" file so that hertz can share the same "go module" with other projects when it is a subproject +- Add the ability to reference third-party IDL products in the "handler", so that IDL products can be maintained separately in the third-party repository and not stored in the project directory, further enhancing IDL management capabilities ### Best Practices We have rewritten "[biz-demo/easy-note](https://github.com/cloudwego/biz-demo/pull/26)" with "hz v0.6.0" to take advantage of the following hz features -* Generate hertz client call code for accessing "api server" based on IDL using the capabilities of "hz client" -* Reorganize the "api server" code with custom "router_dir", "handler_dir", and "model_dir" options, and remove the "biz" directory restriction -* Use the ability to "search up go.mod" so that "api server" can share the same "go module" as a subproject of "easy-note" -* Use the ability of "handler to refer to third-party IDL products" and the ability of "hz model" to store IDL products separately in the "easy-note" project and not in the "api server" subproject + +- Generate hertz client call code for accessing "api server" based on IDL using the capabilities of "hz client" +- Reorganize the "api server" code with custom "router_dir", "handler_dir", and "model_dir" options, and remove the "biz" directory restriction +- Use the ability to "search up go.mod" so that "api server" can share the same "go module" as a subproject of "easy-note" +- Use the ability of "handler to refer to third-party IDL products" and the ability of "hz model" to store IDL products separately in the "easy-note" project and not in the "api server" subproject ## Full Release Note The complete Release Note can refer to: -* Hertz: https://github.com/cloudwego/hertz/releases/tag/v0.6.0 -* Hz(scaffolding): https://github.com/cloudwego/hertz/releases/tag/cmd%2Fhz%2Fv0.6.0 + +- Hertz: https://github.com/cloudwego/hertz/releases/tag/v0.6.0 +- Hz(scaffolding): https://github.com/cloudwego/hertz/releases/tag/cmd%2Fhz%2Fv0.6.0 diff --git a/content/en/blog/releases/Hertz/release-v070.md b/content/en/blog/releases/Hertz/release-v070.md index df2c9374e7..91f357ebb2 100644 --- a/content/en/blog/releases/Hertz/release-v070.md +++ b/content/en/blog/releases/Hertz/release-v070.md @@ -9,24 +9,28 @@ description: > In version 0.7.0 of Hertz, in addition to regular iterative optimization, we also brought several important features. ## Refactor Binding + In version 0.7.0 of Hertz,we refactored the binding feature for Hertz ->https://github.com/cloudwego/hertz/pull/541 + +> https://github.com/cloudwego/hertz/pull/541 ### Description Of Refactoring + In version 0.7.0 of Hertz,we refactored the binding feature for Hertz to better support user requirements。This refactoring has the following characteristics: -* Consistent functionality: - - Binder: After the refactoring, we have implemented a default Binder within Hertz, which has the same functionality as before. The previous binding capabilities have been implemented as extensions under hertz-contrib. - - Validator: We are still using go-tagexpr as the default implementation to ensure consistent functionality. -* Converged configuration: - - Before the refactoring, the behavior of parameter binding was mostly configured through global parameters, which could lead to conflicts when multiple components were configured. - - After the refactoring, the binding and validation configurations are injected into the Hertz Engine through `BindConfig` and `ValidateConfig` struct using the 'WithOption' function. This not only unifies the configuration format but also avoids configuration conflicts. -* Customizable Binder and Validator: - - Custom Binder: You can use "WithCustomBinder" to inject your own custom Binder. We have already provided an extension called hertz-contrib/binding/go_tagexpr. - - Custom Validator: You can use "WithCustomValidator" to inject your own custom Validator. We have also extended go-playground/validator for this purpose. -* Performance improvements: The refactoring has resulted in improved binding performance compared to the previous version. Please refer to the benchmark data below for more details. +- Consistent functionality: + - Binder: After the refactoring, we have implemented a default Binder within Hertz, which has the same functionality as before. The previous binding capabilities have been implemented as extensions under hertz-contrib. + - Validator: We are still using go-tagexpr as the default implementation to ensure consistent functionality. +- Converged configuration: + - Before the refactoring, the behavior of parameter binding was mostly configured through global parameters, which could lead to conflicts when multiple components were configured. + - After the refactoring, the binding and validation configurations are injected into the Hertz Engine through `BindConfig` and `ValidateConfig` struct using the 'WithOption' function. This not only unifies the configuration format but also avoids configuration conflicts. +- Customizable Binder and Validator: + - Custom Binder: You can use "WithCustomBinder" to inject your own custom Binder. We have already provided an extension called hertz-contrib/binding/go_tagexpr. + - Custom Validator: You can use "WithCustomValidator" to inject your own custom Validator. We have also extended go-playground/validator for this purpose. +- Performance improvements: The refactoring has resulted in improved binding performance compared to the previous version. Please refer to the benchmark data below for more details. ### Usage + ```go package main @@ -45,10 +49,12 @@ func main() { ``` ### Benchmark Data + https://github.com/cloudwego/hertz-benchmark/tree/main/binding ## Full Release Note The complete Release Note can refer to: -* Hertz: https://github.com/cloudwego/hertz/releases/tag/v0.7.0 -* Hz(scaffolding): https://github.com/cloudwego/hertz/releases/tag/cmd%2Fhz%2Fv0.7.0 + +- Hertz: https://github.com/cloudwego/hertz/releases/tag/v0.7.0 +- Hz(scaffolding): https://github.com/cloudwego/hertz/releases/tag/cmd%2Fhz%2Fv0.7.0 diff --git a/content/en/blog/releases/Hertz/release-v080.md b/content/en/blog/releases/Hertz/release-v080.md index 548a68da11..971110f8fd 100644 --- a/content/en/blog/releases/Hertz/release-v080.md +++ b/content/en/blog/releases/Hertz/release-v080.md @@ -9,14 +9,18 @@ description: > In Hertz v0.8.0, in addition to the regular iterative optimization, we have also introduced an important feature. ## Partitioned cookies + In Hertz v0.8.0, we support the partitioned cookies feature. ->https://github.com/cloudwego/hertz/pull/1041 + +> https://github.com/cloudwego/hertz/pull/1041 ### Background + Third-party cookies provide the ability for cross-site tracking for the web, and their existence poses a huge threat to the privacy and security of web users. Chrome will disable third-party cookies for 1% of users starting from Quarter 1 of 2024, and gradually expand the disabling scope to 100% starting from the third quarter of 2024. Partitioned Cookies Cookies Having Independent Partitioned State (CHIPS) serve as an alternative to third-party cookies, providing the ability to carry third-party cookies on cross-site requests. #### Set Partitioned Cookies with the Set-Cookie Header + ``` Set-Cookie header: Set-Cookie: __Host-name=value; Secure; Path=/; SameSite=None; Partitioned; @@ -25,9 +29,11 @@ Set-Cookie: __Host-name=value; Secure; Path=/; SameSite=None; Partitioned; ### How to #### Upgrade Hertz version + Hertz added support for Partitioned Cookies in v0.8.0. You need to upgrade to > = v0.8.0 to use Partitioned Cookies. #### How to use Partitioned Cookies + Currently, Hertz supports Partitioned Cookies, but does not yet support passing whether it is Partitioned through SetCookie. We will add this feature in the next minor version. Before that, you can refer to the following code example to use Partitioned Cookies. ``` @@ -82,5 +88,5 @@ curl -v http://localhost:8888/partitioned < Set-Cookie: user=hertz; max-age=1; domain=localhost; path=/; HttpOnly; secure; SameSite=None; Partitioned < * Connection #0 to host localhost left intact -{"partitioned":"yes"}% -``` \ No newline at end of file +{"partitioned":"yes"}% +``` diff --git a/content/en/blog/releases/Kitex/_index.md b/content/en/blog/releases/Kitex/_index.md index 8cad80ba7e..c86ebc7203 100644 --- a/content/en/blog/releases/Kitex/_index.md +++ b/content/en/blog/releases/Kitex/_index.md @@ -3,4 +3,4 @@ title: "Kitex Release" linkTitle: "Kitex" projects: ["Kitex"] weight: 1 ---- \ No newline at end of file +--- diff --git a/content/en/blog/releases/Kitex/release-v001.md b/content/en/blog/releases/Kitex/release-v001.md index f30b30ab63..23feacc2bf 100755 --- a/content/en/blog/releases/Kitex/release-v001.md +++ b/content/en/blog/releases/Kitex/release-v001.md @@ -4,7 +4,6 @@ linkTitle: "Release v0.0.1" projects: ["Kitex"] date: 2021-07-12 description: > - --- -Kitex project initialization. \ No newline at end of file +Kitex project initialization. diff --git a/content/en/blog/releases/Kitex/release-v002.md b/content/en/blog/releases/Kitex/release-v002.md index 88475fae03..e44a41b503 100644 --- a/content/en/blog/releases/Kitex/release-v002.md +++ b/content/en/blog/releases/Kitex/release-v002.md @@ -4,7 +4,6 @@ linkTitle: "Release v0.0.2" projects: ["Kitex"] date: 2021-07-30 description: > - --- ## Improvement: diff --git a/content/en/blog/releases/Kitex/release-v003.md b/content/en/blog/releases/Kitex/release-v003.md index 512ba0f6b7..0051995f6d 100644 --- a/content/en/blog/releases/Kitex/release-v003.md +++ b/content/en/blog/releases/Kitex/release-v003.md @@ -4,9 +4,8 @@ linkTitle: "Release v0.0.3" projects: ["Kitex"] date: 2021-08-01 description: > - --- ## Bugfix: -- Prevent connection pool from being overridden. \ No newline at end of file +- Prevent connection pool from being overridden. diff --git a/content/en/blog/releases/Kitex/release-v004.md b/content/en/blog/releases/Kitex/release-v004.md index c73139552f..200fb74181 100644 --- a/content/en/blog/releases/Kitex/release-v004.md +++ b/content/en/blog/releases/Kitex/release-v004.md @@ -4,7 +4,6 @@ linkTitle: "Release v0.0.4" projects: ["Kitex"] date: 2021-08-26 description: > - --- ## Improvement: diff --git a/content/en/blog/releases/Kitex/release-v005.md b/content/en/blog/releases/Kitex/release-v005.md index bd74c44e0f..9524ac6f32 100644 --- a/content/en/blog/releases/Kitex/release-v005.md +++ b/content/en/blog/releases/Kitex/release-v005.md @@ -4,7 +4,6 @@ linkTitle: "Release v0.0.5" projects: ["Kitex"] date: 2021-09-26 description: > - --- ## Feature: diff --git a/content/en/blog/releases/Kitex/release-v008.md b/content/en/blog/releases/Kitex/release-v008.md index fba5f4901a..943a4b5b3b 100644 --- a/content/en/blog/releases/Kitex/release-v008.md +++ b/content/en/blog/releases/Kitex/release-v008.md @@ -6,29 +6,29 @@ date: 2021-11-05 description: > --- -## Improvement: +## Improvement: - Use shard rings to reduce lock overhead in connpool. - Fill upstream information to rpcinfo from TTheader, for printing useful log when decode error happened. - Move unlink uds operation to CreateListener. - Replace sync.Mutex by sync.RWMutex of event.go and ring_single.go. -## Bugfix: +## Bugfix: - Fix netpollmux shard index overflow. -- Remove reflection of `WithCircuitBreaker` option arguments to prevent data-race. +- Remove reflection of `WithCircuitBreaker` option arguments to prevent data-race. - Fix rpc finished error may happen small probability in failure retry scenario && add sample check for retry circuit breaking. - Fix a test case mistake in endpoint_test.go. -- Modify longconn variable name to conn. +- Modify longconn variable name to conn. -## Tool: +## Tool: -- Kitex codegen tool supports passing through thrift-go plugin arguments. +- Kitex codegen tool supports passing through thrift-go plugin arguments. -## Docs: +## Docs: -- Use a link to the the kitex-benchmark repository to replace the performance section in README. +- Use a link to the the kitex-benchmark repository to replace the performance section in README. -## Dependency Change: +## Dependency Change: -- github.com/tidwall/gjson: v1.8.0 -> v1.9.3 \ No newline at end of file +- github.com/tidwall/gjson: v1.8.0 -> v1.9.3 diff --git a/content/en/blog/releases/Kitex/release-v010.md b/content/en/blog/releases/Kitex/release-v010.md index 741f60a96c..e59a72705f 100644 --- a/content/en/blog/releases/Kitex/release-v010.md +++ b/content/en/blog/releases/Kitex/release-v010.md @@ -4,69 +4,67 @@ linkTitle: "Release v0.1.0" projects: ["Kitex"] date: 2021-12-13 description: > - --- ## Feature ### Generic Call -* Support combined services -* Export SetSeqID and add GetSeqID for binary generic call of server side -* Support close generic client to avoid memory leak - +- Support combined services +- Export SetSeqID and add GetSeqID for binary generic call of server side +- Support close generic client to avoid memory leak ### Log -* Use key=value style in log messages -* Use klog as global log in some logs -* Use the global default logger across kitex -* Print detail loginfo by ctx -* Pass service info to go func which is used to output for troubleshooting +- Use key=value style in log messages +- Use klog as global log in some logs +- Use the global default logger across kitex +- Print detail loginfo by ctx +- Pass service info to go func which is used to output for troubleshooting ### Option -* Add NewThriftCodecDisableFastMode to disable FastWrite/Read -* Add server option - WithReusePort -* Default rpc timeout = 0 +- Add NewThriftCodecDisableFastMode to disable FastWrite/Read +- Add server option - WithReusePort +- Default rpc timeout = 0 ### Proxy -* Proxy add ContextHandler interface to support passing initialization context to mwBuilder -* Register Dump in lbcache to diagnosis -* Pass RPCConfig to proxy.Config +- Proxy add ContextHandler interface to support passing initialization context to mwBuilder +- Register Dump in lbcache to diagnosis +- Pass RPCConfig to proxy.Config ## Improvement -* Reduce heap allocation -* Optimize mux performance -* Recycle grpc codec buffer by close linkbuffer -* Distinguish ErrRPCFinish in cost info of backup request -* Move mux.ShardQueue to netpoll, rename sharedMap to shardMap -* Add container length encoding guard in fast api +- Reduce heap allocation +- Optimize mux performance +- Recycle grpc codec buffer by close linkbuffer +- Distinguish ErrRPCFinish in cost info of backup request +- Move mux.ShardQueue to netpoll, rename sharedMap to shardMap +- Add container length encoding guard in fast api ## Bugfix -* Enable server error handle middleware -* Adjust Balancer initialization in lbcache -* Init TraceCtl when it is nil (only affect unit test) -* Set default rpctimeout and disable timeout logic if rpctimeout == 0 -* Defaultlogger wrong calldepth -* Rename BackwardProxy to ReverseProxy -* Avoid nil panic in grpc keepalive -* Fix hidden dangers about grpc -* Fix exception missing in void method -* Fix mistake dump info when instances change. +- Enable server error handle middleware +- Adjust Balancer initialization in lbcache +- Init TraceCtl when it is nil (only affect unit test) +- Set default rpctimeout and disable timeout logic if rpctimeout == 0 +- Defaultlogger wrong calldepth +- Rename BackwardProxy to ReverseProxy +- Avoid nil panic in grpc keepalive +- Fix hidden dangers about grpc +- Fix exception missing in void method +- Fix mistake dump info when instances change. ## Docs -* Fix link in readme_zh -* Remove docs; maintain cloudwego.io only +- Fix link in readme_zh +- Remove docs; maintain cloudwego.io only ## Netpoll API Change -* Adapt netpoll.Writer.Append API +- Adapt netpoll.Writer.Append API ## Dependency Change -* github.com/cloudwego/netpoll: v0.0.4 -> v0.1.2 +- github.com/cloudwego/netpoll: v0.0.4 -> v0.1.2 diff --git a/content/en/blog/releases/Kitex/release-v012.md b/content/en/blog/releases/Kitex/release-v012.md index c0d0b2867d..f950cb67e2 100644 --- a/content/en/blog/releases/Kitex/release-v012.md +++ b/content/en/blog/releases/Kitex/release-v012.md @@ -4,18 +4,17 @@ linkTitle: "Release v0.1.2" projects: ["Kitex"] date: 2021-12-22 description: > - --- ## Hotfix -* Fix some gRPC request bugs which are involved by v0.1.0 -* Fix mistake gRPC method path when no package definition in IDL +- Fix some gRPC request bugs which are involved by v0.1.0 +- Fix mistake gRPC method path when no package definition in IDL ## Dependency Change -* Chore: upgrade netpoll-http2 to fix the problem about large request package (>4K) in streaming +- Chore: upgrade netpoll-http2 to fix the problem about large request package (>4K) in streaming ## Chore -* Chore: use GitHub's `PULL_REQUEST_TEMPLATE` to create a PR +- Chore: use GitHub's `PULL_REQUEST_TEMPLATE` to create a PR diff --git a/content/en/blog/releases/Kitex/release-v013.md b/content/en/blog/releases/Kitex/release-v013.md index 4726e79e60..c80b90167c 100644 --- a/content/en/blog/releases/Kitex/release-v013.md +++ b/content/en/blog/releases/Kitex/release-v013.md @@ -4,23 +4,22 @@ linkTitle: "Release v0.1.3" projects: ["Kitex"] date: 2021-12-30 description: > - --- ## Feature -* Transmit the Base from client to server for getting the caller info in JSON generic +- Transmit the Base from client to server for getting the caller info in JSON generic ## Bugfix -* Fix(grpc): fix metric missing method tag in streaming -* Fix(generic): fix the incompatible modification about base64 binary in the JSON and HTTP generic -* Fix(grpc): fix the bug of grpc flow control, which brings the problem of continuous timeout +- Fix(grpc): fix metric missing method tag in streaming +- Fix(generic): fix the incompatible modification about base64 binary in the JSON and HTTP generic +- Fix(grpc): fix the bug of grpc flow control, which brings the problem of continuous timeout ## CI -* Add scenario tests +- Add scenario tests ## Chore -* update the [ROADMAP](https://github.com/cloudwego/kitex/blob/develop/ROADMAP.md) +- update the [ROADMAP](https://github.com/cloudwego/kitex/blob/develop/ROADMAP.md) diff --git a/content/en/blog/releases/Kitex/release-v014.md b/content/en/blog/releases/Kitex/release-v014.md index 213074a855..526654bd4e 100644 --- a/content/en/blog/releases/Kitex/release-v014.md +++ b/content/en/blog/releases/Kitex/release-v014.md @@ -4,27 +4,25 @@ linkTitle: "Release v0.1.4" projects: ["Kitex"] date: 2022-01-18 description: > - --- ## Improvement -* Optimize(log): don't print timeout log in rpctimeout middleware -* Optimize(log): adjust default log level to info -* Optimize(gRPC): lock the sendAt avoid grpc bdp data race +- Optimize(log): don't print timeout log in rpctimeout middleware +- Optimize(log): adjust default log level to info +- Optimize(gRPC): lock the sendAt avoid grpc bdp data race ## Bugfix -* Fix(client-connection): fix a connection leaking bug that happens when clients fail at Send -* Fix(timeout): fix TimeoutAdjust won't work when set in middleware builder - +- Fix(client-connection): fix a connection leaking bug that happens when clients fail at Send +- Fix(timeout): fix TimeoutAdjust won't work when set in middleware builder ## Tool -* Fix(tool): fix protobuf handler arguments name -> kitex will generate a stream type named "{{.ServiceName}}{{.Name}}Server" for each streaming server, -> but in handler.go kitex use "{{.ServiceName}}{{.RawName}}Server" as stream name. +- Fix(tool): fix protobuf handler arguments name + > kitex will generate a stream type named "{{.ServiceName}}{{.Name}}Server" for each streaming server, + > but in handler.go kitex use "{{.ServiceName}}{{.RawName}}Server" as stream name. ## Chore -* Style: remove unnecessary type conversions +- Style: remove unnecessary type conversions diff --git a/content/en/blog/releases/Kitex/release-v020.md b/content/en/blog/releases/Kitex/release-v020.md index 26b1b85146..78da9d4d16 100644 --- a/content/en/blog/releases/Kitex/release-v020.md +++ b/content/en/blog/releases/Kitex/release-v020.md @@ -4,27 +4,26 @@ linkTitle: "Release v0.2.0" projects: ["Kitex"] date: 2022-02-24 description: > - --- ## Feature -* Feat(grpc): support options to set the internal params of gRPC -* Feat(kerror): add new func WithCauseAndExtraMsg for basicError -* Feat(rpcinfo): add FreezeRPCInfo to support asynchronous context usage -* Feat(codec): default codec supports size limit +- Feat(grpc): support options to set the internal params of gRPC +- Feat(kerror): add new func WithCauseAndExtraMsg for basicError +- Feat(rpcinfo): add FreezeRPCInfo to support asynchronous context usage +- Feat(codec): default codec supports size limit ## Bugfix -* Fix(remotecli): fix bug that released connections may be reused -* Fix(generic): generic call supports extended services -* Fix(generic): fix generic call oneway flag +- Fix(remotecli): fix bug that released connections may be reused +- Fix(generic): generic call supports extended services +- Fix(generic): fix generic call oneway flag ## Optimise -* Optimize(retry): improve retry success rate when do failure retry +- Optimize(retry): improve retry success rate when do failure retry ## Chore -* Chore: upgrade netpoll to v0.2.0 -* Chore:add third party license +- Chore: upgrade netpoll to v0.2.0 +- Chore:add third party license diff --git a/content/en/blog/releases/Kitex/release-v021.md b/content/en/blog/releases/Kitex/release-v021.md index 1b5a1955f7..f995b4b40e 100644 --- a/content/en/blog/releases/Kitex/release-v021.md +++ b/content/en/blog/releases/Kitex/release-v021.md @@ -4,33 +4,32 @@ linkTitle: "Release v0.2.1" projects: ["Kitex"] date: 2022-03-24 description: > - --- ## Bugfix -* [[#383](https://github.com/cloudwego/kitex/pull/383) ] fix(generic): detect circular dependency in thrift IDL when using generic call. -* [[#359](https://github.com/cloudwego/kitex/pull/359) ] fix(tool): fix streaming import missing in protobuf combine service. -* [[#363](https://github.com/cloudwego/kitex/pull/363) ] fix(client): fix a bug that sequence ID of oneway requests are not encoded and lower the loss rate of oneway requests. -* [[#367](https://github.com/cloudwego/kitex/pull/367) ] fix(generic/tool): combine services may have duplicate loading of the same service. +- [[#383](https://github.com/cloudwego/kitex/pull/383) ] fix(generic): detect circular dependency in thrift IDL when using generic call. +- [[#359](https://github.com/cloudwego/kitex/pull/359) ] fix(tool): fix streaming import missing in protobuf combine service. +- [[#363](https://github.com/cloudwego/kitex/pull/363) ] fix(client): fix a bug that sequence ID of oneway requests are not encoded and lower the loss rate of oneway requests. +- [[#367](https://github.com/cloudwego/kitex/pull/367) ] fix(generic/tool): combine services may have duplicate loading of the same service. ## Optimise -* [[#362](https://github.com/cloudwego/kitex/pull/362) ] optimize(diagnosis): lbcache is global, it doesn't need register ProbeFunc for diagnosis. -* [[#374](https://github.com/cloudwego/kitex/pull/374) ] optimize(rpcinfo): RPCInfo.To().Tag() use instance tag instead of remoteinfo tag firstly. -* [[#355](https://github.com/cloudwego/kitex/pull/355) ] optimize(connpool): adjust minMaxIdleTimeout to 2s. -* [[#354](https://github.com/cloudwego/kitex/pull/354) ] optimize(hook): adding locks to onServerStart and onShutdown, acquire the corresponding lock when doing some read and write operations like RegisterStartHook and range in server.Run(). -* [[#331](https://github.com/cloudwego/kitex/pull/331) ] optimize(discovery): add error definition ErrInstanceNotFound which is used in the service discovery module. +- [[#362](https://github.com/cloudwego/kitex/pull/362) ] optimize(diagnosis): lbcache is global, it doesn't need register ProbeFunc for diagnosis. +- [[#374](https://github.com/cloudwego/kitex/pull/374) ] optimize(rpcinfo): RPCInfo.To().Tag() use instance tag instead of remoteinfo tag firstly. +- [[#355](https://github.com/cloudwego/kitex/pull/355) ] optimize(connpool): adjust minMaxIdleTimeout to 2s. +- [[#354](https://github.com/cloudwego/kitex/pull/354) ] optimize(hook): adding locks to onServerStart and onShutdown, acquire the corresponding lock when doing some read and write operations like RegisterStartHook and range in server.Run(). +- [[#331](https://github.com/cloudwego/kitex/pull/331) ] optimize(discovery): add error definition ErrInstanceNotFound which is used in the service discovery module. ## Refactor -* [[#352](https://github.com/cloudwego/kitex/pull/352) ] refactor(event): delete additional atomic operations and replace them with a normal operation. -* [[#343](https://github.com/cloudwego/kitex/pull/343) ] refactor(loadbalancer): merge BuildWeightedVirtualNodes function into buildVirtualNodes function, make it easier to maintain. +- [[#352](https://github.com/cloudwego/kitex/pull/352) ] refactor(event): delete additional atomic operations and replace them with a normal operation. +- [[#343](https://github.com/cloudwego/kitex/pull/343) ] refactor(loadbalancer): merge BuildWeightedVirtualNodes function into buildVirtualNodes function, make it easier to maintain. ## Chore -* [[#376](https://github.com/cloudwego/kitex/pull/376) ] chore: upgrade choleraehyq/pid for Go 1.18. +- [[#376](https://github.com/cloudwego/kitex/pull/376) ] chore: upgrade choleraehyq/pid for Go 1.18. ## Docs -* [[#364](https://github.com/cloudwego/kitex/pull/364) ] docs: update readme with new blog. +- [[#364](https://github.com/cloudwego/kitex/pull/364) ] docs: update readme with new blog. diff --git a/content/en/blog/releases/Kitex/release-v030.md b/content/en/blog/releases/Kitex/release-v030.md index 7f0b750cb8..283d29b5ee 100644 --- a/content/en/blog/releases/Kitex/release-v030.md +++ b/content/en/blog/releases/Kitex/release-v030.md @@ -4,48 +4,47 @@ linkTitle: "Release v0.3.0" projects: ["Kitex"] date: 2022-04-29 description: > - --- ## Feature -* [[#366](https://github.com/cloudwego/kitex/pull/366), [#426](https://github.com/cloudwego/kitex/pull/426) ] feat(client): support warming-up for kitex client -* [[#395](https://github.com/cloudwego/kitex/pull/395) ] feat(mux): support gracefully shutdown in connection multiplexing -* [[#399](https://github.com/cloudwego/kitex/pull/399) ] feat(protobuf): add fastpb protocol API and support it in the pkg/remote/codec module +- [[#366](https://github.com/cloudwego/kitex/pull/366), [#426](https://github.com/cloudwego/kitex/pull/426) ] feat(client): support warming-up for kitex client +- [[#395](https://github.com/cloudwego/kitex/pull/395) ] feat(mux): support gracefully shutdown in connection multiplexing +- [[#399](https://github.com/cloudwego/kitex/pull/399) ] feat(protobuf): add fastpb protocol API and support it in the pkg/remote/codec module ## Optimise -* [[#402](https://github.com/cloudwego/kitex/pull/402) ] optimize(connpool): export getCommonReporter in pkg/remote/connpool -* [[#389](https://github.com/cloudwego/kitex/pull/389) ] optimize(rpcinfo): fill TransportProtocol, PackageName fields into RPCInfo of the server side after decoding +- [[#402](https://github.com/cloudwego/kitex/pull/402) ] optimize(connpool): export getCommonReporter in pkg/remote/connpool +- [[#389](https://github.com/cloudwego/kitex/pull/389) ] optimize(rpcinfo): fill TransportProtocol, PackageName fields into RPCInfo of the server side after decoding ## Bugfix -* [[#413](https://github.com/cloudwego/kitex/pull/413) ] fix(mux): set PayloadCodec for sendMsg in NetpollMux trans handler to fix generic request codec error.[issue #411](https://github.com/cloudwego/kitex/issues/411) -* [[#406](https://github.com/cloudwego/kitex/pull/406) ] fix(grpc): fix the sending and receiving logic about http2 framer, such as preventing the peer unable to receive the framer in time -* [[#398](https://github.com/cloudwego/kitex/pull/398) ] fix(utils): fix the bug that Dump() func in ring.go can't dump the accurate data in ring shards -* [[#428](https://github.com/cloudwego/kitex/pull/428) ] fix(trans): close connection when flush data fails to avoid memory leak +- [[#413](https://github.com/cloudwego/kitex/pull/413) ] fix(mux): set PayloadCodec for sendMsg in NetpollMux trans handler to fix generic request codec error.[issue #411](https://github.com/cloudwego/kitex/issues/411) +- [[#406](https://github.com/cloudwego/kitex/pull/406) ] fix(grpc): fix the sending and receiving logic about http2 framer, such as preventing the peer unable to receive the framer in time +- [[#398](https://github.com/cloudwego/kitex/pull/398) ] fix(utils): fix the bug that Dump() func in ring.go can't dump the accurate data in ring shards +- [[#428](https://github.com/cloudwego/kitex/pull/428) ] fix(trans): close connection when flush data fails to avoid memory leak ## Tool -* [[#340](https://github.com/cloudwego/kitex/pull/340) ] tool(protobuf): redesign and implement new protobuf gen code called fastpb which doesn't use reflection and only supports proto3 +- [[#340](https://github.com/cloudwego/kitex/pull/340) ] tool(protobuf): redesign and implement new protobuf gen code called fastpb which doesn't use reflection and only supports proto3 ## Chore -* [[#396](https://github.com/cloudwego/kitex/pull/396) ] chore: replace cespare/xxhash with xxhash3 from bytedance/gopkg -* [[#400](https://github.com/cloudwego/kitex/pull/400) ] chore: upgrade go version of workflow to 1.18 -* [[#407](https://github.com/cloudwego/kitex/pull/407) ] chore: add a separate file to declare the use of gRPC source code +- [[#396](https://github.com/cloudwego/kitex/pull/396) ] chore: replace cespare/xxhash with xxhash3 from bytedance/gopkg +- [[#400](https://github.com/cloudwego/kitex/pull/400) ] chore: upgrade go version of workflow to 1.18 +- [[#407](https://github.com/cloudwego/kitex/pull/407) ] chore: add a separate file to declare the use of gRPC source code ## Test -* [[#401](https://github.com/cloudwego/kitex/pull/401) ] test: add ut for kitex/server package -* [[#393](https://github.com/cloudwego/kitex/pull/393) ] test: add ut for pkg/remote/bound package -* [[#403](https://github.com/cloudwego/kitex/pull/403) ] test: add netpollmux unit test -* [[#401](https://github.com/cloudwego/kitex/pull/401) ] test: add klog unit test -* [[#392](https://github.com/cloudwego/kitex/pull/392) ] test(utils): add UT for utils and fix inaccurate err throw in json.go -* [[#373](https://github.com/cloudwego/kitex/pull/373), [#432](https://github.com/cloudwego/kitex/pull/432), [#434](https://github.com/cloudwego/kitex/pull/434) ] test(grpc): add gRPC transport unit tests, promoting the coverage to 76% -* [[#424](https://github.com/cloudwego/kitex/pull/424) ] test(transmeta): supplementary of unit tests for http2 and ttheader implementations of MetaHandler/StreamingMetaHandler in pkg/transmeta. +- [[#401](https://github.com/cloudwego/kitex/pull/401) ] test: add ut for kitex/server package +- [[#393](https://github.com/cloudwego/kitex/pull/393) ] test: add ut for pkg/remote/bound package +- [[#403](https://github.com/cloudwego/kitex/pull/403) ] test: add netpollmux unit test +- [[#401](https://github.com/cloudwego/kitex/pull/401) ] test: add klog unit test +- [[#392](https://github.com/cloudwego/kitex/pull/392) ] test(utils): add UT for utils and fix inaccurate err throw in json.go +- [[#373](https://github.com/cloudwego/kitex/pull/373), [#432](https://github.com/cloudwego/kitex/pull/432), [#434](https://github.com/cloudwego/kitex/pull/434) ] test(grpc): add gRPC transport unit tests, promoting the coverage to 76% +- [[#424](https://github.com/cloudwego/kitex/pull/424) ] test(transmeta): supplementary of unit tests for http2 and ttheader implementations of MetaHandler/StreamingMetaHandler in pkg/transmeta. ## Dependency Change -* github.com/cloudwego/netpoll: v0.2.0 -> v0.2.2 -* github.com/bytedance/gopkg: 20210910103821-e4efae9c17c3 -> 20220413063733-65bf48ffb3a7 +- github.com/cloudwego/netpoll: v0.2.0 -> v0.2.2 +- github.com/bytedance/gopkg: 20210910103821-e4efae9c17c3 -> 20220413063733-65bf48ffb3a7 diff --git a/content/en/blog/releases/Kitex/release-v032.md b/content/en/blog/releases/Kitex/release-v032.md index f6df7a18e3..d8004ee99b 100644 --- a/content/en/blog/releases/Kitex/release-v032.md +++ b/content/en/blog/releases/Kitex/release-v032.md @@ -8,49 +8,48 @@ description: > ## Feature -* [[#473](https://github.com/cloudwego/kitex/pull/473)] feat(grpc): support short connection for gRPC unary. -* [[#431](https://github.com/cloudwego/kitex/pull/431)] feat(limiter): extend outside limiter implementation and fix problems of rate limiter of multiplexed server. +- [[#473](https://github.com/cloudwego/kitex/pull/473)] feat(grpc): support short connection for gRPC unary. +- [[#431](https://github.com/cloudwego/kitex/pull/431)] feat(limiter): extend outside limiter implementation and fix problems of rate limiter of multiplexed server. ## Optimize -* [[#465](https://github.com/cloudwego/kitex/pull/465)] optimize(ttheader): set remote address for client-side after decoding TTHeader. -* [[#466](https://github.com/cloudwego/kitex/pull/466)] optimize(mux): wrap ErrReadTimeout with ErrRPCTimeout in mux scenario. -* [[#425](https://github.com/cloudwego/kitex/pull/425)] optimize(limiter): promise tokens of the first second don't exceed limit significantly. +- [[#465](https://github.com/cloudwego/kitex/pull/465)] optimize(ttheader): set remote address for client-side after decoding TTHeader. +- [[#466](https://github.com/cloudwego/kitex/pull/466)] optimize(mux): wrap ErrReadTimeout with ErrRPCTimeout in mux scenario. +- [[#425](https://github.com/cloudwego/kitex/pull/425)] optimize(limiter): promise tokens of the first second don't exceed limit significantly. ## Bugfix -* [[#485](https://github.com/cloudwego/kitex/pull/485)] fix(grpc): fix the incorrect integer conversion. -* [[#474](https://github.com/cloudwego/kitex/pull/474)] fix(trans): fix detection handler panic when conn inactive early. -* [[#445](https://github.com/cloudwego/kitex/pull/445)] fix(retry): race problems of callTimes in retry and some fields of rpcStats. -* [[#471](https://github.com/cloudwego/kitex/pull/471)] fix(retry): callCosts race in backup request. +- [[#485](https://github.com/cloudwego/kitex/pull/485)] fix(grpc): fix the incorrect integer conversion. +- [[#474](https://github.com/cloudwego/kitex/pull/474)] fix(trans): fix detection handler panic when conn inactive early. +- [[#445](https://github.com/cloudwego/kitex/pull/445)] fix(retry): race problems of callTimes in retry and some fields of rpcStats. +- [[#471](https://github.com/cloudwego/kitex/pull/471)] fix(retry): callCosts race in backup request. ## Test -* [[#404](https://github.com/cloudwego/kitex/pull/404)] test: add unit test for pkg/retry. -* [[#439](https://github.com/cloudwego/kitex/pull/439), [#472](https://github.com/cloudwego/kitex/pull/472)] test: add unit test for pkg/remote/remotecli. -* [[#462](https://github.com/cloudwego/kitex/pull/462), [#457](https://github.com/cloudwego/kitex/pull/457)] test: add unit test for pkg/remote/trans/nphttp2/grpc. -* [[#420](https://github.com/cloudwego/kitex/pull/420)] test: add ut for pkg/remote/trans/nphttp2. +- [[#404](https://github.com/cloudwego/kitex/pull/404)] test: add unit test for pkg/retry. +- [[#439](https://github.com/cloudwego/kitex/pull/439), [#472](https://github.com/cloudwego/kitex/pull/472)] test: add unit test for pkg/remote/remotecli. +- [[#462](https://github.com/cloudwego/kitex/pull/462), [#457](https://github.com/cloudwego/kitex/pull/457)] test: add unit test for pkg/remote/trans/nphttp2/grpc. +- [[#420](https://github.com/cloudwego/kitex/pull/420)] test: add ut for pkg/remote/trans/nphttp2. ## Refactor -* [[#464](https://github.com/cloudwego/kitex/pull/464)] refactor(ttheader): change protocol id of Kitex Protobuf in TTHeader and promise the change is compatible with the old version. +- [[#464](https://github.com/cloudwego/kitex/pull/464)] refactor(ttheader): change protocol id of Kitex Protobuf in TTHeader and promise the change is compatible with the old version. ## Chore -* [[#453](https://github.com/cloudwego/kitex/pull/453), [#475](https://github.com/cloudwego/kitex/pull/475)] chore: upgrade netpoll and bytedance/gopkg. -* [[#458](https://github.com/cloudwego/kitex/pull/458)] chore: fix ci reviewdog and pr ut didn't run. -* [[#454](https://github.com/cloudwego/kitex/pull/454)] chore: use self-hosted ci to optimize speed. -* [[#449](https://github.com/cloudwego/kitex/pull/449)] chore: fix github issue template. +- [[#453](https://github.com/cloudwego/kitex/pull/453), [#475](https://github.com/cloudwego/kitex/pull/475)] chore: upgrade netpoll and bytedance/gopkg. +- [[#458](https://github.com/cloudwego/kitex/pull/458)] chore: fix ci reviewdog and pr ut didn't run. +- [[#454](https://github.com/cloudwego/kitex/pull/454)] chore: use self-hosted ci to optimize speed. +- [[#449](https://github.com/cloudwego/kitex/pull/449)] chore: fix github issue template. ## Style -* [[#486](https://github.com/cloudwego/kitex/pull/486)] style(trans): add comment for detection trans handler. +- [[#486](https://github.com/cloudwego/kitex/pull/486)] style(trans): add comment for detection trans handler. ## Docs -* [[#482](https://github.com/cloudwego/kitex/pull/482)] docs: update FAQ of readme. +- [[#482](https://github.com/cloudwego/kitex/pull/482)] docs: update FAQ of readme. ## Dependency Change -* github.com/cloudwego/netpoll: v0.2.2 -> v0.2.4 - +- github.com/cloudwego/netpoll: v0.2.2 -> v0.2.4 diff --git a/content/en/blog/releases/Kitex/release-v040.md b/content/en/blog/releases/Kitex/release-v040.md index 6a58a26007..6b0b2f8f75 100644 --- a/content/en/blog/releases/Kitex/release-v040.md +++ b/content/en/blog/releases/Kitex/release-v040.md @@ -9,18 +9,18 @@ description: > ## **Introduction to Key Changes** ### **Feature** + 1. **Retry enhancement**: Support user-defined result retry; Support request-level configuration (priority is higher than Neptune). See [retry guide](/docs/kitex/tutorials/service-governance/retry/) for details 2. **Frugal (Thrift)**: Support default value of IDL; No codec code is supported by using frugal. See [frugal](/docs/kitex/tutorials/advanced-feature/codec_frugal/) for details -3. **Tool-Protobuf**: Support depend on external libraries with go_package, see [Notes for Using Protobuf IDLs](/docs/kitex/tutorials/code-gen/code_generation/#notes-for-using-protobuf-idls); Support Guess IDL type from the file extension, it is unnecessary to specify the type param when generating the protobuf code +3. **Tool-Protobuf**: Support depend on external libraries with go_package, see [Notes for Using Protobuf IDLs](/docs/kitex/tutorials/code-gen/code_generation/#notes-for-using-protobuf-idls); Support Guess IDL type from the file extension, it is unnecessary to specify the type param when generating the protobuf code 4. **Fastpb(protobuf)**: Support fastpb to optimize performance of protobuf, and it is integrated into Kite by default. See [fastpb](/docs/kitex/tutorials/code-gen/fastpb/) for details 5. **Generic Call**: Support HTTP+Protobuf generic call 6. **Kitex lib supports Windows**: You can use kitex running on Windows (Kitex tool still doesn't support) - ### **Optimization & Bugfix** -1. **Performance Optimization**: gRPC unary throughput increased by 46-70%, and 51% - 70% higher than the official gRPC framework throughput. See [benchmark](https://github.com/cloudwego/kitex-benchmark) for details -2. **Generic Call**: Support default value defined in thrift IDL for HTTP / Map / JSON Generic +1. **Performance Optimization**: gRPC unary throughput increased by 46-70%, and 51% - 70% higher than the official gRPC framework throughput. See [benchmark](https://github.com/cloudwego/kitex-benchmark) for details +2. **Generic Call**: Support default value defined in thrift IDL for HTTP / Map / JSON Generic --- @@ -28,53 +28,53 @@ description: > ### Feature -* [[#571](https://github.com/cloudwego/kitex/pull/571)] feat(protobuf): integrate [fastpb](https://github.com/cloudwego/fastpb) into kitex, refer to [doc](/docs/kitex/tutorials/code-gen/fastpb/). -* [[#592](https://github.com/cloudwego/kitex/pull/592)] feat(generic): add default value defined in thrift idl for HTTP/Map/JSON generic call. -* [[#600](https://github.com/cloudwego/kitex/pull/600)] feat(thrift): support no codec gen-code when using frugal. -* [[#607](https://github.com/cloudwego/kitex/pull/607), [#610](https://github.com/cloudwego/kitex/pull/610)] feat(proxyless): add option for xDS extension. Support traffic route, timeout config and service discovery based on xDS. -* [[#541](https://github.com/cloudwego/kitex/pull/541)] feat(trans): Add the go net extension to the transport layer, and choose it as the transmission mode by default in Windows OS. -* [[#540](https://github.com/cloudwego/kitex/pull/540)] feat(retry): support retry with specified error or response and add retry option for setup method retry policy. -* [[#533](https://github.com/cloudwego/kitex/pull/533)] feat(generic): js_conv annotation of generic call supports map type conversion. +- [[#571](https://github.com/cloudwego/kitex/pull/571)] feat(protobuf): integrate [fastpb](https://github.com/cloudwego/fastpb) into kitex, refer to [doc](/docs/kitex/tutorials/code-gen/fastpb/). +- [[#592](https://github.com/cloudwego/kitex/pull/592)] feat(generic): add default value defined in thrift idl for HTTP/Map/JSON generic call. +- [[#600](https://github.com/cloudwego/kitex/pull/600)] feat(thrift): support no codec gen-code when using frugal. +- [[#607](https://github.com/cloudwego/kitex/pull/607), [#610](https://github.com/cloudwego/kitex/pull/610)] feat(proxyless): add option for xDS extension. Support traffic route, timeout config and service discovery based on xDS. +- [[#541](https://github.com/cloudwego/kitex/pull/541)] feat(trans): Add the go net extension to the transport layer, and choose it as the transmission mode by default in Windows OS. +- [[#540](https://github.com/cloudwego/kitex/pull/540)] feat(retry): support retry with specified error or response and add retry option for setup method retry policy. +- [[#533](https://github.com/cloudwego/kitex/pull/533)] feat(generic): js_conv annotation of generic call supports map type conversion. ### Optimize -* [[#522](https://github.com/cloudwego/kitex/pull/522), [#538](https://github.com/cloudwego/kitex/pull/538), [#605](https://github.com/cloudwego/kitex/pull/605)] perf(grpc): optimize performance for gRPC protocol. -* [[#590](https://github.com/cloudwego/kitex/pull/590)] optimize(tool): guess IDL type from file extension. -* [[#559](https://github.com/cloudwego/kitex/pull/559)] optimize(timeout): use wrap func to check timeout err in timeout middleware which can ignore logs customized timeout err. -* [[#581](https://github.com/cloudwego/kitex/pull/581)] optimize(tool): kitex tool usage add cmd example. +- [[#522](https://github.com/cloudwego/kitex/pull/522), [#538](https://github.com/cloudwego/kitex/pull/538), [#605](https://github.com/cloudwego/kitex/pull/605)] perf(grpc): optimize performance for gRPC protocol. +- [[#590](https://github.com/cloudwego/kitex/pull/590)] optimize(tool): guess IDL type from file extension. +- [[#559](https://github.com/cloudwego/kitex/pull/559)] optimize(timeout): use wrap func to check timeout err in timeout middleware which can ignore logs customized timeout err. +- [[#581](https://github.com/cloudwego/kitex/pull/581)] optimize(tool): kitex tool usage add cmd example. ### Bugfix -* [[#564](https://github.com/cloudwego/kitex/pull/564)] fix(oneway): discard oneway conn after sending complete, or subsequent requests that send to the same connection may get blocked until the oneway request gets processed by the server. -* [[#577](https://github.com/cloudwego/kitex/pull/577), [#584](https://github.com/cloudwego/kitex/pull/584), [#602](https://github.com/cloudwego/kitex/pull/602)] fix(rpcinfo): fix rpcinfo reuse problem in longconn scene. -* [[#578](https://github.com/cloudwego/kitex/pull/578)] fix: fix long pool dump panic. -* [[#583](https://github.com/cloudwego/kitex/pull/583)] fix(tool): fix misusing of package name in protobuf generated code. -* [[#587](https://github.com/cloudwego/kitex/pull/587)] fix(tool): skip proto files with external import paths when generates code. -* [[#594](https://github.com/cloudwego/kitex/pull/594)] fix(generic): support the tag format of the escape double quotes in single quotes to be compatible with the logic of the old version. -* [[#595](https://github.com/cloudwego/kitex/pull/595)] fix: fix nil union panic in BLength. -* [[#589](https://github.com/cloudwego/kitex/pull/589), [#596](https://github.com/cloudwego/kitex/pull/596)] fix(frugal): fix frugal build tag. +- [[#564](https://github.com/cloudwego/kitex/pull/564)] fix(oneway): discard oneway conn after sending complete, or subsequent requests that send to the same connection may get blocked until the oneway request gets processed by the server. +- [[#577](https://github.com/cloudwego/kitex/pull/577), [#584](https://github.com/cloudwego/kitex/pull/584), [#602](https://github.com/cloudwego/kitex/pull/602)] fix(rpcinfo): fix rpcinfo reuse problem in longconn scene. +- [[#578](https://github.com/cloudwego/kitex/pull/578)] fix: fix long pool dump panic. +- [[#583](https://github.com/cloudwego/kitex/pull/583)] fix(tool): fix misusing of package name in protobuf generated code. +- [[#587](https://github.com/cloudwego/kitex/pull/587)] fix(tool): skip proto files with external import paths when generates code. +- [[#594](https://github.com/cloudwego/kitex/pull/594)] fix(generic): support the tag format of the escape double quotes in single quotes to be compatible with the logic of the old version. +- [[#595](https://github.com/cloudwego/kitex/pull/595)] fix: fix nil union panic in BLength. +- [[#589](https://github.com/cloudwego/kitex/pull/589), [#596](https://github.com/cloudwego/kitex/pull/596)] fix(frugal): fix frugal build tag. ### Refactor -* [[#566](https://github.com/cloudwego/kitex/pull/566)] refactor(metainfo): remove noused metakeys of HTTP2 Header. -* [[#593](https://github.com/cloudwego/kitex/pull/593)] refactor(trans): support specify Listener for server by option WithListener, the priority is higher than WithServiceAddr. -* [[#582](https://github.com/cloudwego/kitex/pull/582)] refactor(tool): use templates by embedding and export APIs for external usage for kitex tool. +- [[#566](https://github.com/cloudwego/kitex/pull/566)] refactor(metainfo): remove noused metakeys of HTTP2 Header. +- [[#593](https://github.com/cloudwego/kitex/pull/593)] refactor(trans): support specify Listener for server by option WithListener, the priority is higher than WithServiceAddr. +- [[#582](https://github.com/cloudwego/kitex/pull/582)] refactor(tool): use templates by embedding and export APIs for external usage for kitex tool. ### Test -* [[#579](https://github.com/cloudwego/kitex/pull/579)] test: add ut for long pool dump function. -* [[#608](https://github.com/cloudwego/kitex/pull/608)] test: fix data race in TestClientConnDecoupledFromApplicationRead. -* [[#609](https://github.com/cloudwego/kitex/pull/609)] test: fix gonet ut avoid testing port conflicts. -* [[#480](https://github.com/cloudwego/kitex/pull/480)] test: add unit test for client package. +- [[#579](https://github.com/cloudwego/kitex/pull/579)] test: add ut for long pool dump function. +- [[#608](https://github.com/cloudwego/kitex/pull/608)] test: fix data race in TestClientConnDecoupledFromApplicationRead. +- [[#609](https://github.com/cloudwego/kitex/pull/609)] test: fix gonet ut avoid testing port conflicts. +- [[#480](https://github.com/cloudwego/kitex/pull/480)] test: add unit test for client package. ### Chore -* [[#558](https://github.com/cloudwego/kitex/pull/558)] ci: fix setup-python github action. -* [[#487](https://github.com/cloudwego/kitex/pull/487)] ci: workflow add golangci-lint. -* [[#580](https://github.com/cloudwego/kitex/pull/580)] chore: fix the typos in remote module about go net. -* [[#601](https://github.com/cloudwego/kitex/pull/601)] chore: fixed some typos and replaced some defunct functions. -* [[#604](https://github.com/cloudwego/kitex/pull/604)] chore: upgrade fastpb to v0.0.2. -* [[#603](https://github.com/cloudwego/kitex/pull/603)] chore: upgrade frugal to v0.1.2. +- [[#558](https://github.com/cloudwego/kitex/pull/558)] ci: fix setup-python github action. +- [[#487](https://github.com/cloudwego/kitex/pull/487)] ci: workflow add golangci-lint. +- [[#580](https://github.com/cloudwego/kitex/pull/580)] chore: fix the typos in remote module about go net. +- [[#601](https://github.com/cloudwego/kitex/pull/601)] chore: fixed some typos and replaced some defunct functions. +- [[#604](https://github.com/cloudwego/kitex/pull/604)] chore: upgrade fastpb to v0.0.2. +- [[#603](https://github.com/cloudwego/kitex/pull/603)] chore: upgrade frugal to v0.1.2. ### Dependency Change @@ -93,4 +93,3 @@ new imported: github.com/cloudwego/fastpb v0.0.2 github.com/jhump/protoreflect v1.8.2 - diff --git a/content/en/blog/releases/Kitex/release-v043.md b/content/en/blog/releases/Kitex/release-v043.md index 0cfa42fc27..c8dee4389f 100644 --- a/content/en/blog/releases/Kitex/release-v043.md +++ b/content/en/blog/releases/Kitex/release-v043.md @@ -11,7 +11,7 @@ description: > ### **Feature** 1. **Extend the Generated Code of client/server**: Add a new feature which can extend generated client.go/server.go with config file. It is applicable to the scenario for customizing the unified suite. See [Extend the Templates of Service Generated Code]([/docs/kitex/tutorials/code-gen/template_extension/]) for details. -2. **Biz Customized Exception** : Add supporting to return customized biz error which can distinguish with RPC error. See [Business Exception](/docs/kitex/tutorials/basic-feature/bizstatuserr/), [Proposal](https://github.com/cloudwego/kitex/issues/511). +2. **Biz Customized Exception** : Add supporting to return customized biz error which can distinguish with RPC error. See [Business Exception](/docs/kitex/tutorials/basic-feature/bizstatuserr/), [Proposal](https://github.com/cloudwego/kitex/issues/511). 3. **Request Profiler** : Add a new feature to do profiler for requests which can be used for cost statistics. 4. **Context Middleware** : Add Context Middleware which is used for adding request-level middlewares. @@ -26,55 +26,54 @@ description: > ### Feature -* [[#691](https://github.com/cloudwego/kitex/pull/691)] feat(client): add context middleware which is used for adding request-level middlewares. -* [[#649](https://github.com/cloudwego/kitex/pull/649)] feat(connpool): new long connection pool with minIdle config and idle connections cleanup. -* [[#672](https://github.com/cloudwego/kitex/pull/672)] feat(grpc): add kitex grpc metadata api to get header, tailer, and peer address metadata. -* [[#613](https://github.com/cloudwego/kitex/pull/613)] feat(exception): support customized biz error which can distinguish with RPC error. -* [[#670](https://github.com/cloudwego/kitex/pull/670)] feat(exception): support error format. -* [[#678](https://github.com/cloudwego/kitex/pull/678)] feat(tool): add git and record param for cmd. -* [[#662](https://github.com/cloudwego/kitex/pull/662)] feat(tool): support frugal precompile (pretouch) when new client or server. -* [[#657](https://github.com/cloudwego/kitex/pull/657)] feat(tool): support template extension. -* [[#527](https://github.com/cloudwego/kitex/pull/527)] feat(profiler): profiler for rpc request which can be used for cost statistics. +- [[#691](https://github.com/cloudwego/kitex/pull/691)] feat(client): add context middleware which is used for adding request-level middlewares. +- [[#649](https://github.com/cloudwego/kitex/pull/649)] feat(connpool): new long connection pool with minIdle config and idle connections cleanup. +- [[#672](https://github.com/cloudwego/kitex/pull/672)] feat(grpc): add kitex grpc metadata api to get header, tailer, and peer address metadata. +- [[#613](https://github.com/cloudwego/kitex/pull/613)] feat(exception): support customized biz error which can distinguish with RPC error. +- [[#670](https://github.com/cloudwego/kitex/pull/670)] feat(exception): support error format. +- [[#678](https://github.com/cloudwego/kitex/pull/678)] feat(tool): add git and record param for cmd. +- [[#662](https://github.com/cloudwego/kitex/pull/662)] feat(tool): support frugal precompile (pretouch) when new client or server. +- [[#657](https://github.com/cloudwego/kitex/pull/657)] feat(tool): support template extension. +- [[#527](https://github.com/cloudwego/kitex/pull/527)] feat(profiler): profiler for rpc request which can be used for cost statistics. ### Optimize -* [[#690](https://github.com/cloudwego/kitex/pull/690)] optimize(meta): remove error logic for adding default metaHandler in #503. -* [[#638](https://github.com/cloudwego/kitex/pull/638)] optimize(generic): httppb generic support map/list elem type as struct. -* [[#641](https://github.com/cloudwego/kitex/pull/641)] optimize(tool): add warnings comments for oneway methods. +- [[#690](https://github.com/cloudwego/kitex/pull/690)] optimize(meta): remove error logic for adding default metaHandler in #503. +- [[#638](https://github.com/cloudwego/kitex/pull/638)] optimize(generic): httppb generic support map/list elem type as struct. +- [[#641](https://github.com/cloudwego/kitex/pull/641)] optimize(tool): add warnings comments for oneway methods. ### Fix -* [[#611](https://github.com/cloudwego/kitex/pull/611)] fix(client): fix resource leaks caused by Finalizer not being triggered in the scenario where clients are created frequently. -* [[#698](https://github.com/cloudwego/kitex/pull/698)] fix(connpool): adjust globalIdle based on the number of connections decreased during the Get. -* [[#636](https://github.com/cloudwego/kitex/pull/636)] fix(connpool): CloseCallback and statistical reporting of connection pool are invalid when the connection pool is reset in `ForwardProxy`. -* [[#647](https://github.com/cloudwego/kitex/pull/647)] fix(grpc): update grpc connection window size when initial and synchronize grpc pr #5459. -* [[#639](https://github.com/cloudwego/kitex/pull/639)] fix(generic): marshalling list in generic and enabling forJSON reader option for MapThriftGeneric. -* [[#655](https://github.com/cloudwego/kitex/pull/655)] fix(generic): numeric constant parsing fails when used as generic default value. -* [[#654](https://github.com/cloudwego/kitex/pull/654)] fix(frugal): fix compilation error when using lower go version. -* [[#682](https://github.com/cloudwego/kitex/pull/682)] fix(profiler): profiler stops pprof profile. -* [[#637](https://github.com/cloudwego/kitex/pull/637)] fix(tool): fix imports in handler.go template. -* [[#630](https://github.com/cloudwego/kitex/pull/630)] fix(tool): remove redundant kitex comments for file that do not declare an interface. -* [[#627](https://github.com/cloudwego/kitex/pull/627)] fix(tool): fix import missing when having different alias for the same path. +- [[#611](https://github.com/cloudwego/kitex/pull/611)] fix(client): fix resource leaks caused by Finalizer not being triggered in the scenario where clients are created frequently. +- [[#698](https://github.com/cloudwego/kitex/pull/698)] fix(connpool): adjust globalIdle based on the number of connections decreased during the Get. +- [[#636](https://github.com/cloudwego/kitex/pull/636)] fix(connpool): CloseCallback and statistical reporting of connection pool are invalid when the connection pool is reset in `ForwardProxy`. +- [[#647](https://github.com/cloudwego/kitex/pull/647)] fix(grpc): update grpc connection window size when initial and synchronize grpc pr #5459. +- [[#639](https://github.com/cloudwego/kitex/pull/639)] fix(generic): marshalling list in generic and enabling forJSON reader option for MapThriftGeneric. +- [[#655](https://github.com/cloudwego/kitex/pull/655)] fix(generic): numeric constant parsing fails when used as generic default value. +- [[#654](https://github.com/cloudwego/kitex/pull/654)] fix(frugal): fix compilation error when using lower go version. +- [[#682](https://github.com/cloudwego/kitex/pull/682)] fix(profiler): profiler stops pprof profile. +- [[#637](https://github.com/cloudwego/kitex/pull/637)] fix(tool): fix imports in handler.go template. +- [[#630](https://github.com/cloudwego/kitex/pull/630)] fix(tool): remove redundant kitex comments for file that do not declare an interface. +- [[#627](https://github.com/cloudwego/kitex/pull/627)] fix(tool): fix import missing when having different alias for the same path. ### Refactor -* [[#651](https://github.com/cloudwego/kitex/pull/651)] refactor(server): server handler read/write interface return new context. +- [[#651](https://github.com/cloudwego/kitex/pull/651)] refactor(server): server handler read/write interface return new context. ### Docs -* [[#656](https://github.com/cloudwego/kitex/pull/656)] docs: remove wrong message in CONTRIBUTING.md. -* [[#683](https://github.com/cloudwego/kitex/pull/683)] docs(kerrors): fix kerrors WithCauseAndExtraMsg method comment. -* [[#625](https://github.com/cloudwego/kitex/pull/625)] chore: fix grammar of pull request template. -* [[#623](https://github.com/cloudwego/kitex/pull/623)] chore: modify the template of pull request. +- [[#656](https://github.com/cloudwego/kitex/pull/656)] docs: remove wrong message in CONTRIBUTING.md. +- [[#683](https://github.com/cloudwego/kitex/pull/683)] docs(kerrors): fix kerrors WithCauseAndExtraMsg method comment. +- [[#625](https://github.com/cloudwego/kitex/pull/625)] chore: fix grammar of pull request template. +- [[#623](https://github.com/cloudwego/kitex/pull/623)] chore: modify the template of pull request. ### Test & CI -* [[#646](https://github.com/cloudwego/kitex/pull/646)] test: fix ut failure caused by InitRPCInfoFunc not setting rpcinfo. -* [[#680](https://github.com/cloudwego/kitex/pull/680)] test: fix retry test race. -* [[#661](https://github.com/cloudwego/kitex/pull/661)] test: make wpool tests more stable. -* [[#643](https://github.com/cloudwego/kitex/pull/643)] test: add test for detection server handler. -* [[#632](https://github.com/cloudwego/kitex/pull/632)] test: replace handwritten mock classes with gomock auto-generated classes. -* [[#697](https://github.com/cloudwego/kitex/pull/697)] chore(ci): fixed skywalking-eyes version. -* [[#652](https://github.com/cloudwego/kitex/pull/652)] chore(ci): delete repeated tests to reduce unit tests cost times. -* [[#588](https://github.com/cloudwego/kitex/pull/588)] chore(ci): support codecov. - +- [[#646](https://github.com/cloudwego/kitex/pull/646)] test: fix ut failure caused by InitRPCInfoFunc not setting rpcinfo. +- [[#680](https://github.com/cloudwego/kitex/pull/680)] test: fix retry test race. +- [[#661](https://github.com/cloudwego/kitex/pull/661)] test: make wpool tests more stable. +- [[#643](https://github.com/cloudwego/kitex/pull/643)] test: add test for detection server handler. +- [[#632](https://github.com/cloudwego/kitex/pull/632)] test: replace handwritten mock classes with gomock auto-generated classes. +- [[#697](https://github.com/cloudwego/kitex/pull/697)] chore(ci): fixed skywalking-eyes version. +- [[#652](https://github.com/cloudwego/kitex/pull/652)] chore(ci): delete repeated tests to reduce unit tests cost times. +- [[#588](https://github.com/cloudwego/kitex/pull/588)] chore(ci): support codecov. diff --git a/content/en/blog/releases/Kitex/release-v050.md b/content/en/blog/releases/Kitex/release-v050.md index 87fd0db77b..70bbdf672d 100644 --- a/content/en/blog/releases/Kitex/release-v050.md +++ b/content/en/blog/releases/Kitex/release-v050.md @@ -10,10 +10,10 @@ description: > ### **Feature** -**1. Fallback: Support fallback for client-side** +**1. Fallback: Support fallback for client-side** -When the RPC requests fail, users usually have some degradation measures to ensure the effective response (for example, construct the default response after the request timeout or circuit breaker). -Kitex's Fallback supports the processing of all error requests. At the same time, because business errors are usually returned through the Resp (BaseResp field), Kitex also supports the processing of Resp. +When the RPC requests fail, users usually have some degradation measures to ensure the effective response (for example, construct the default response after the request timeout or circuit breaker). +Kitex's Fallback supports the processing of all error requests. At the same time, because business errors are usually returned through the Resp (BaseResp field), Kitex also supports the processing of Resp. Refer to [Fallback](/docs/kitex/tutorials/service-governance/fallback/). **2. Kitex - gRPC: Client add TLS option configuration** @@ -23,10 +23,9 @@ Setup via client.WithGRPCTLSConfig option. **3. Kitex - Tool** - **Support customized scaffold templates**, refer to [Custom Scaffold Template](/docs/kitex/tutorials/code-gen/custom_tpl/) -- **Support specifying the directory for generating code**, refer to [Code Generation Tool -gen-path](/docs/kitex/tutorials/code-gen/code_generation/#-gen-path) +- **Support specifying the directory for generating code**, refer to [Code Generation Tool -gen-path](/docs/kitex/tutorials/code-gen/code_generation/#-gen-path) - **Support using protoc plugin**, refer to [Code Generation Tool -protobuf-plugin](/docs/kitex/tutorials/code-gen/code_generation/#-protobuf-plugin) - ### **Optimization** **1. Loadbalance:Use Weighted Round Robin algo as default Loadbalance policy** @@ -61,7 +60,7 @@ Upgrade the frugal and pid dependency lib to support go 1.20. ### Optimize - [[#750](https://github.com/cloudwego/kitex/pull/750)] optimize(generic): generic call write zero value for required and default fields to meet the specification of apache thrift and keep consistent with normal thrift encode of Kitex. -- [[#739](https://github.com/cloudwego/kitex/pull/739)] optimize(generic): modify the url routing to align with Hertz for HTTP generic call +- [[#739](https://github.com/cloudwego/kitex/pull/739)] optimize(generic): modify the url routing to align with Hertz for HTTP generic call - [[#752](https://github.com/cloudwego/kitex/pull/752)] optimize(ttheader): attach part of ttheader binary into error when readKVInfo failed, which is useful for troubleshooting - [[#821](https://github.com/cloudwego/kitex/pull/821)] optimize(config): add DeepCopy() & Equals() to circuitbreaker.CBConfig and retry.Policy - [[#827](https://github.com/cloudwego/kitex/pull/827)] optimize: revise the remoteInfo of retry call, using the remoteInfo of the RPCCall that returns @@ -101,4 +100,3 @@ Upgrade the frugal and pid dependency lib to support go 1.20. - [[#761](https://github.com/cloudwego/kitex/pull/761)] docs: update README.md @fuergaosi233 - [[#817](https://github.com/cloudwego/kitex/pull/817), [#832](https://github.com/cloudwego/kitex/pull/832)] chore: upgrade dependency lib to adapt go 1.20 - [[#772](https://github.com/cloudwego/kitex/pull/772)] chore: modify kitex gen code meta file name from kitex.yaml to kitex_info.yaml - diff --git a/content/en/blog/releases/Kitex/release-v052.md b/content/en/blog/releases/Kitex/release-v052.md index a874d1c1b7..f6ada31b98 100644 --- a/content/en/blog/releases/Kitex/release-v052.md +++ b/content/en/blog/releases/Kitex/release-v052.md @@ -5,6 +5,7 @@ projects: ["Kitex"] date: 2023-04-21 description: > --- + ## **Introduction to Key Changes** ### **Feature** @@ -14,39 +15,39 @@ description: > 3. Error code: fine grained rpc timeout error code 4. Thrift Fast Codec: support unknown fields - * Background of "unknown fields": In Thrift, adding fields in the IDL is transparent to the party that has not updated the IDL. Updating the IDL and generating code is necessary to access new fields, which requires all downstream nodes to upgrade when a node on the invocation Chain updates the IDL. + - Background of "unknown fields": In Thrift, adding fields in the IDL is transparent to the party that has not updated the IDL. Updating the IDL and generating code is necessary to access new fields, which requires all downstream nodes to upgrade when a node on the invocation Chain updates the IDL. - * "Unknown fields" supports retaining unrecognized fields. For fields that do not exist in the IDL, they are read and set in the `_unknownFields` field of the struct. + - "Unknown fields" supports retaining unrecognized fields. For fields that do not exist in the IDL, they are read and set in the `_unknownFields` field of the struct. - * Usage: `kitex -thrift keep_unknown_fields your.thrift` + - Usage: `kitex -thrift keep_unknown_fields your.thrift` ### **Fix** + 1. Result retry: fix the issue that the result retry becomes invalid after failure retry policy is modified dynamically ----- +--- ## **Full Release Log** -Feature: ---- -* [[#887](https://github.com/cloudwego/kitex/pull/887)] feat(retry): add configuration to support disable timeout retry when do failure retry, which is for the non-idempotent request -* [[#881](https://github.com/cloudwego/kitex/pull/881)] feat(tool): support codegen in windows -* [[#880](https://github.com/cloudwego/kitex/pull/880)] feat(rpctimeout): fine grained rpc timeout error code -* [[#872](https://github.com/cloudwego/kitex/pull/872)] feat(thrift): support unknown fields in fast codec +## Feature: -Optimize: ---- -* [[#884](https://github.com/cloudwego/kitex/pull/884)] optimize(rpcinfo): RPCInfo.To().Tag() use instance tag instead of remoteinfo tag firstly +- [[#887](https://github.com/cloudwego/kitex/pull/887)] feat(retry): add configuration to support disable timeout retry when do failure retry, which is for the non-idempotent request +- [[#881](https://github.com/cloudwego/kitex/pull/881)] feat(tool): support codegen in windows +- [[#880](https://github.com/cloudwego/kitex/pull/880)] feat(rpctimeout): fine grained rpc timeout error code +- [[#872](https://github.com/cloudwego/kitex/pull/872)] feat(thrift): support unknown fields in fast codec -Fix: ---- -* [[#896](https://github.com/cloudwego/kitex/pull/896)] fix(remoteinfo): fix the race problem caused by non-deepcopy CopyFrom of remoteinfo -* [[#892](https://github.com/cloudwego/kitex/pull/892)] fix(grpc): comment error log for the error of ReadFrame. -* [[#889](https://github.com/cloudwego/kitex/pull/889)] fix(retry): result retry doesn’t work after failure retry policy is modified dynamically -* [[#866](https://github.com/cloudwego/kitex/pull/866)] fix(grpc): no need to set context return by sendMsg/recvMsg to the context of stream +## Optimize: -Chore: ---- -* [[#898](https://github.com/cloudwego/kitex/pull/898)] chore: modify template for PR to check the modification of user doc -* [[#854](https://github.com/cloudwego/kitex/pull/854)] style(nphttp2): keep struct receiver name same +- [[#884](https://github.com/cloudwego/kitex/pull/884)] optimize(rpcinfo): RPCInfo.To().Tag() use instance tag instead of remoteinfo tag firstly + +## Fix: + +- [[#896](https://github.com/cloudwego/kitex/pull/896)] fix(remoteinfo): fix the race problem caused by non-deepcopy CopyFrom of remoteinfo +- [[#892](https://github.com/cloudwego/kitex/pull/892)] fix(grpc): comment error log for the error of ReadFrame. +- [[#889](https://github.com/cloudwego/kitex/pull/889)] fix(retry): result retry doesn’t work after failure retry policy is modified dynamically +- [[#866](https://github.com/cloudwego/kitex/pull/866)] fix(grpc): no need to set context return by sendMsg/recvMsg to the context of stream + +## Chore: +- [[#898](https://github.com/cloudwego/kitex/pull/898)] chore: modify template for PR to check the modification of user doc +- [[#854](https://github.com/cloudwego/kitex/pull/854)] style(nphttp2): keep struct receiver name same diff --git a/content/en/blog/releases/Kitex/release-v060.md b/content/en/blog/releases/Kitex/release-v060.md index f74b8db8c7..d0c2e4fec5 100644 --- a/content/en/blog/releases/Kitex/release-v060.md +++ b/content/en/blog/releases/Kitex/release-v060.md @@ -37,16 +37,16 @@ Function `buildVirtualNodes` in Kitex consistency hash load balancer uses `virtu Fix the issue that the records that long connection pool reuses connections successfully didn't report. - ### **Other** Upgrade netpoll library dependency to v0.4.0 and support for [configmanager] ( https://github.com/cloudwego/configmanager ) v0.2.0. ----- +--- ## **Full Release Log** ## Feature: + - [[#923](https://github.com/cloudwego/kitex/pull/923)] feat(grpc): grpc client set header and trailer to context by default and provide api to get header from ctx - [[#891](https://github.com/cloudwego/kitex/pull/891)] feat: support to service-inline rpc client and server, which can transfer the rpc call as func call. The feature needs to be used with the generation tool - [[#946](https://github.com/cloudwego/kitex/pull/946)] feat: default server handler support executing Read function by trans pipeline @@ -56,6 +56,7 @@ Upgrade netpoll library dependency to v0.4.0 and support for [configmanager] ( h - [[#897](https://github.com/cloudwego/kitex/pull/897)] feat: support loop_service in custom template ## Optimize: + - [[#961](https://github.com/cloudwego/kitex/pull/961)] optimize(tool): optimize kitex tool tpl with -use param - [[#966](https://github.com/cloudwego/kitex/pull/966)] optimize(ttheader): add type check for headerFlags of TTheader - [[#919](https://github.com/cloudwego/kitex/pull/919)] optimize: replace go func with GoFunc to avoid panic @@ -65,6 +66,7 @@ Upgrade netpoll library dependency to v0.4.0 and support for [configmanager] ( h - [[#941](https://github.com/cloudwego/kitex/pull/941)] optimize(callopt): optimize the debug info of callopt to reduce the possibility of slice grow ## Fix: + - [[#963](https://github.com/cloudwego/kitex/pull/963)] fix(generic): generic-map writeInt8 fails on byte - [[#901](https://github.com/cloudwego/kitex/pull/901)] fix(mux): mux connection asynccallback dont create new goroutine and server wait all crrst packets received by client - [[#921](https://github.com/cloudwego/kitex/pull/921)] fix(loadbalance): fix consisthash byte[] length @@ -72,14 +74,17 @@ Upgrade netpoll library dependency to v0.4.0 and support for [configmanager] ( h - [[#927](https://github.com/cloudwego/kitex/pull/927)] fix(connpool): long connection pool reports reuse success using reporter ## Refactor: + - [[#958](https://github.com/cloudwego/kitex/pull/958)] refactor(errorHandler): refactor the definition of error handler to get more information to handle error - [[#943](https://github.com/cloudwego/kitex/pull/943)] refactor(client): refactor client.Call to improve readability - [[#560](https://github.com/cloudwego/kitex/pull/560)] refactor: refactor server detection trans handler to support custom registration ## Tests: + - [[#900](https://github.com/cloudwego/kitex/pull/900)] test(generic): add thrift reflection (using dynamicgo) generic call example ## Chore: + - [[#976](https://github.com/cloudwego/kitex/pull/976)] chore: upgrade netpoll to v0.4.0 and thriftgo to v0.2.11 - [[#956](https://github.com/cloudwego/kitex/pull/956)] chore: update configmanager version to v0.2.0 - [[#948](https://github.com/cloudwego/kitex/pull/948)] chore: format with goimports -local github.com/cloudwego/kitex diff --git a/content/en/blog/releases/Kitex/release-v070.md b/content/en/blog/releases/Kitex/release-v070.md index 8e30142d0a..0e9f34fafb 100644 --- a/content/en/blog/releases/Kitex/release-v070.md +++ b/content/en/blog/releases/Kitex/release-v070.md @@ -5,9 +5,11 @@ projects: ["Kitex"] date: 2023-08-14 description: > --- + ## **Introduction to Key Changes** ### Features + **1. gRPC Compression Support** Implemented compression support for Kitex gRPC, allowing compression methods like gzip to reduce payload size. @@ -17,6 +19,7 @@ Implemented compression support for Kitex gRPC, allowing compression methods lik Utilized the [local-session](https://github.com/cloudwego/localsession) component for context propagation in fallback requests, addressing the issue of broken microservice chains caused by missing ctx. ### Optimizations + **1. Unserialized Unknown Fields** Implemented unserialization of unknown fields, resulting in a performance improvement of approximately 6x to 7x on FastCodec. See details in [#1017](https://github.com/cloudwego/kitex/pull/1017). @@ -25,15 +28,16 @@ Implemented unserialization of unknown fields, resulting in a performance improv Integrated [dynamicgo](https://github.com/cloudwego/dynamicgo) into Kitex's generic module to enhance performance of JSON/HTTP generic invocations (+50% to 200%). -### Others +### Others Upgraded Thriftgo library dependency to v0.3.0, adding support for Thriftgo reflection, enabling runtime access to IDL metadata. ----- +--- ## **Full Release Log** ### Feature: + - [[#1053](https://github.com/cloudwego/kitex/pull/1053)] feat(retry): support to distinguish local retry request - [[#1058](https://github.com/cloudwego/kitex/pull/1058)] feat(retry): support delete retry policy dynamically - [[#1000](https://github.com/cloudwego/kitex/pull/1000)] feat(grpc): support grpc compress @@ -44,6 +48,7 @@ Upgraded Thriftgo library dependency to v0.3.0, adding support for Thriftgo refl - [[#1019](https://github.com/cloudwego/kitex/pull/1019)] feat(lb): interleaved weighted round-robin load balancer ### Optimize: + - [[#1064](https://github.com/cloudwego/kitex/pull/1064)] optimize: check header max size when ttheader encode - [[#1017](https://github.com/cloudwego/kitex/pull/1017)] optimize: implement unknown field function without serialization - [[#1036](https://github.com/cloudwego/kitex/pull/1036)] optimize(protobuf): ignore err when (un)marshal empty req/resp @@ -53,6 +58,7 @@ Upgraded Thriftgo library dependency to v0.3.0, adding support for Thriftgo refl - [[#1020](https://github.com/cloudwego/kitex/pull/1020)] optimize: add nil check for MethodInfo which get from ServiceInfo in client.Call to ignore panic ### Fix: + - [[#1073](https://github.com/cloudwego/kitex/pull/1073)] fix: fix failure retryer dump panic - [[#1067](https://github.com/cloudwego/kitex/pull/1067)] fix: slim template with deepcopy - [[#1055](https://github.com/cloudwego/kitex/pull/1055)] fix: ignore SIGHUP when run with nohup @@ -67,6 +73,7 @@ Upgraded Thriftgo library dependency to v0.3.0, adding support for Thriftgo refl - [[#994](https://github.com/cloudwego/kitex/pull/994)] fix(tool): fix kitex tool git repo pulling logic ### Chore: + - [[#1074](https://github.com/cloudwego/kitex/pull/1074)] chore: update thriftgo to v0.3.0 - [[#1031](https://github.com/cloudwego/kitex/pull/1031)] chore: remove wechat group in readme - [[#1008](https://github.com/cloudwego/kitex/pull/1008)] chore: update dynamicgo to v0.1.1 diff --git a/content/en/blog/releases/Kitex/release-v072.md b/content/en/blog/releases/Kitex/release-v072.md index 6d0cd77454..77a2f2c64e 100644 --- a/content/en/blog/releases/Kitex/release-v072.md +++ b/content/en/blog/releases/Kitex/release-v072.md @@ -5,6 +5,7 @@ projects: ["Kitex"] date: 2023-09-27 description: > --- + ## **Introduction to Key Changes** ### Features @@ -18,7 +19,6 @@ It's recommended to update your current implementation: 1. Initialize a RetryContainer with `retry.NewRetryContainerWithPercentageLimit()` to limit the percentage of retry requests; 2. Add an option `client.WithCloseCallbacks(container.Close)` when initializing a client, in order to release relevant resources when the client is recycled. - ### Optimizations **1. gRPC** @@ -35,19 +35,23 @@ If `MaxIdleGlobal` is not set, it is not limited by default, simplifying the con - Upgrade netpoll to [v0.5.0](https://github.com/cloudwego/netpoll/releases/tag/v0.5.0) - Upgrade frugal to [v0.1.8](https://github.com/cloudwego/frugal/releases/tag/v0.1.8), enable frugal when compiled on go1.21 (note: old versions of frugal are not adapted to go1.21) - ----- +--- ## Full Release Log ### Feature: + - [[#1117](https://github.com/cloudwego/kitex/pull/1117)] feat(retry): support retry percentage limit + ### Optimize: + - [[#1033](https://github.com/cloudwego/kitex/pull/1033)] optimize: no need to check svcInfo twice - [[#1115](https://github.com/cloudwego/kitex/pull/1115)] optimize: rm outdated framed suggestion - [[#1095](https://github.com/cloudwego/kitex/pull/1095)] optimize: add K_METHOD in serviceinline ctx - [[#1107](https://github.com/cloudwego/kitex/pull/1107)] optimize(connpool): set maxIdleGlobal to no limit if not set + ### Fix: + - [[#1116](https://github.com/cloudwego/kitex/pull/1116)] fix: use the last rpcinfo to trace - [[#1104](https://github.com/cloudwego/kitex/pull/1104)] fix: move limiter handler to the last of the inbound handler to get rpcinfo in custom limiter - [[#1103](https://github.com/cloudwego/kitex/pull/1103)] fix: reset all fields of netpoll byte buffer when recycle it @@ -57,15 +61,17 @@ If `MaxIdleGlobal` is not set, it is not limited by default, simplifying the con - [[#1098](https://github.com/cloudwego/kitex/pull/1098)] fix(tool): fix import for codegen template when using slim and unknown fields ### Tests: + - [[#1124](https://github.com/cloudwego/kitex/pull/1124)] test: fix codegen script - [[#1122](https://github.com/cloudwego/kitex/pull/1122)] test: add codegen test - [[#1119](https://github.com/cloudwego/kitex/pull/1119)] test(connpool): modify the idleTimeout ## Chore: + - [[#1133](https://github.com/cloudwego/kitex/pull/1133)] chore: update version v0.7.2 - [[#1125](https://github.com/cloudwego/kitex/pull/1125)] chore: upgrade netpoll to v0.5.0 - [[#1123](https://github.com/cloudwego/kitex/pull/1123)] perf: replace concurrent string builder with lock - [[#1118](https://github.com/cloudwego/kitex/pull/1118)] perf: optimize remote addr setter interface to reduce lock cost of Address() - [[#1110](https://github.com/cloudwego/kitex/pull/1110)] chore: upgrade netpoll to v0.4.2 pre-release - [[#1061](https://github.com/cloudwego/kitex/pull/1061)] chore: netpoll pre release v0.4.2 -- [[#1100](https://github.com/cloudwego/kitex/pull/1100)] chore: enable frugal on go1.21 \ No newline at end of file +- [[#1100](https://github.com/cloudwego/kitex/pull/1100)] chore: enable frugal on go1.21 diff --git a/content/en/blog/releases/Kitex/release-v080.md b/content/en/blog/releases/Kitex/release-v080.md index cb61e069ec..c3422c34f5 100644 --- a/content/en/blog/releases/Kitex/release-v080.md +++ b/content/en/blog/releases/Kitex/release-v080.md @@ -5,9 +5,11 @@ projects: ["Kitex"] date: 2023-11-30 description: > --- + ## **Introduction to Key Changes** ### Features + **1. gRPC Multi-Service Support** Implemented multi-service registration for Kitex gRPC, please refer to [Multiple Services](/docs/kitex/tutorials/advanced-feature/multi_service/). @@ -17,6 +19,7 @@ Implemented multi-service registration for Kitex gRPC, please refer to [Multiple Added methods for easy retrieval of RPC information from RPCInfo, please refer to [Acquire RPC information](/docs/kitex/tutorials/basic-feature/acquire_rpcinfo/). ### Optimizations + **1. Map Generic Call** Map generic call supports returning []byte for binary fields via SetBinaryWithByteSlice option. @@ -25,18 +28,20 @@ Map generic call supports returning []byte for binary fields via SetBinaryWithBy Added an option to disable reusing RPCInfo, facilitating asynchronous usage, please refer to please refer to [Acquire RPC information](/docs/kitex/tutorials/basic-feature/acquire_rpcinfo/#12-asynchronous-usage). - ### Others Upgraded frugal to [v0.1.12](https://github.com/cloudwego/frugal/releases/tag/v0.1.12), fixing some concurrency issues when compiling types, especially the issue when registering new modules which may conflict with sonic. - It's STRONGLY SUGGESTED updating both frugal and sonic to the latest version by - ```shell - go get github.com/cloudwego/frugal@latest - go get github.com/bytedance/sonic@latest - ``` + It's STRONGLY SUGGESTED updating both frugal and sonic to the latest version by + +```shell + go get github.com/cloudwego/frugal@latest + go get github.com/bytedance/sonic@latest +``` + ## **Full Release Log** ### Feature: + [[#1051](https://github.com/cloudwego/kitex/pull/1051)] feat(grpc): support gRPC multi-service on a server [[#1189](https://github.com/cloudwego/kitex/pull/1189)] feat(rpcinfo): add kitexutil methods for the convenience to fetch rpc information from RPCInfo [[#1176](https://github.com/cloudwego/kitex/pull/1176)] feat(tool): add an environment variable to make it easier to debug kitex tool @@ -44,22 +49,28 @@ Upgraded frugal to [v0.1.12](https://github.com/cloudwego/frugal/releases/tag/v0 [[#1172](https://github.com/cloudwego/kitex/pull/1172)] feat(retry): client.WithSpecifiedResultRetry should have higher priority [[#1150](https://github.com/cloudwego/kitex/pull/1150)] feat(proxy): add an interface to customize proxy middleware to replace the default implementation [[#1159](https://github.com/cloudwego/kitex/pull/1159)] feat(generic): support returning []byte for binary fields in map generic -[[#1153](https://github.com/cloudwego/kitex/pull/1153)] feat(retry): add Extra for retry.FailurePolicy for better extension +[[#1153](https://github.com/cloudwego/kitex/pull/1153)] feat(retry): add Extra for retry.FailurePolicy for better extension + ### Optimize: + [[#1187](https://github.com/cloudwego/kitex/pull/1187)] optimize(tool): add an option to keep resp for kitex tool [[#1183](https://github.com/cloudwego/kitex/pull/1183)] optimize(meshheader): retrieve rip from meshheader and write it to TransInfo -[[#1178](https://github.com/cloudwego/kitex/pull/1178)] optimize(bizErr): recurse to obtain BizErr to avoid additional Error encapsulation in the middle, resulting in unwrap results that are not BizErr +[[#1178](https://github.com/cloudwego/kitex/pull/1178)] optimize(bizErr): recurse to obtain BizErr to avoid additional Error encapsulation in the middle, resulting in unwrap results that are not BizErr + ### Fix: + [[#1126](https://github.com/cloudwego/kitex/pull/1126)] fix(generic): the issue of structs cache of generic call has dirty data under multiple services scene [[#1168](https://github.com/cloudwego/kitex/pull/1168)] fix(tool): remove the pointer to java.Object in generated file for [CodecDubbo](https://github.com/kitex-contrib/codec-dubbo) [[#1169](https://github.com/cloudwego/kitex/pull/1169)] fix(tool): empty struct generate wrong struct [[#1166](https://github.com/cloudwego/kitex/pull/1166)] fix(generic): issue of deep copy function generation when map key type is binary -[[#1155](https://github.com/cloudwego/kitex/pull/1155)] fix(tool): add import package 'context' for gRPC client.go +[[#1155](https://github.com/cloudwego/kitex/pull/1155)] fix(tool): add import package 'context' for gRPC client.go ### Tests: -[[#1177](https://github.com/cloudwego/kitex/pull/1177)] test: avoid port conflict + +[[#1177](https://github.com/cloudwego/kitex/pull/1177)] test: avoid port conflict ### Chore: + [[#1190](https://github.com/cloudwego/kitex/pull/1190)] chore: update thriftgo version to v0.3.3 [[#1186](https://github.com/cloudwego/kitex/pull/1186)] chore: update readme with examples and new blogs [[#1185](https://github.com/cloudwego/kitex/pull/1185)] chore: add ci for windows @@ -68,4 +79,4 @@ Upgraded frugal to [v0.1.12](https://github.com/cloudwego/frugal/releases/tag/v0 [[#1164](https://github.com/cloudwego/kitex/pull/1164)] chore: update frugal to v0.1.12 and allow disable frugal by build tag [[#1161](https://github.com/cloudwego/kitex/pull/1161)] chore: update frugal to v0.1.10 [[#1157](https://github.com/cloudwego/kitex/pull/1157)] chore: update frugal to v0.1.9 -[[#1151](https://github.com/cloudwego/kitex/pull/1151)] chore(test): upgrade mockey to latest to compatible with Go1.21 +[[#1151](https://github.com/cloudwego/kitex/pull/1151)] chore(test): upgrade mockey to latest to compatible with Go1.21 diff --git a/content/en/blog/releases/Kitex/release-v090.md b/content/en/blog/releases/Kitex/release-v090.md index 6396cdb3e9..6c7ce56e52 100644 --- a/content/en/blog/releases/Kitex/release-v090.md +++ b/content/en/blog/releases/Kitex/release-v090.md @@ -13,6 +13,7 @@ Below are some important changes: ## **Introduction to Key Changes** ### Features + **1. Thrift Streaming** The Thrift Streaming feature based on gRPC (HTTP2) has been officially released. Users can use Thrift to define their own Streaming requests. To maintain compatibility with IDL parsing, Kitex chooses to use annotation to define stream method. See [Thrift Streaming Usage](/docs/kitex/tutorials/basic-feature/protocol/transport-streaming/thrift_streaming/). This version also improves the monitoring and reporting of Streaming requests, which also applies to gRPC-Protobuf. Note that Thrift is mainly used for data serialization and does not use the Thrift message protocol. @@ -33,7 +34,7 @@ Supported the use of Frugal on ARM64 machines, temporarily supported by Fallback **4. Server level context timeout** -Added server.WithEnableContextTimeout supports adding timeout to context at the server level. And in the new version, Kitex will default pass the client-side timeout in the TTHeader to server-side. Usage please see [Timeout](/docs/kitex/tutorials/service-governance/timeout/). +Added server.WithEnableContextTimeout supports adding timeout to context at the server level. And in the new version, Kitex will default pass the client-side timeout in the TTHeader to server-side. Usage please see [Timeout](/docs/kitex/tutorials/service-governance/timeout/). Note: TTHeader transport protocol is required. @@ -47,8 +48,6 @@ Note: TTHeader transport protocol is required.。 Adding a new LoadBalance method of Alias Method to reduce the time complexity of random weight LoadBalance algorithm. Specified by `client.WithLoadBalancer(loadbalance.NewWeightedRandomWithAliasMethodBalancer())`. - - ### Special Change Kitex v0.9.0 requires Go version must >= 1.17, no longer compatible with Go <= v1.16 (stability requirement must upgrade golang.org/x/library, which introduced Go version limit) @@ -64,6 +63,7 @@ Kitex supports controlling the policies of Timeout, Retry, Circuit Breaker, Limi ## **Full Release Log** ### Feature: + 1. [[#1208](https://github.com/cloudwego/kitex/pull/1208), [#1251](https://github.com/cloudwego/kitex/pull/1251), [#1230](https://github.com/cloudwego/kitex/pull/1230), [#1226](https://github.com/cloudwego/kitex/pull/1226)] feat: support thrift streaming (replacing the protobuf payload of GRPC/HTTP2 with thrift binary) 2. [[#1217](https://github.com/cloudwego/kitex/pull/1217)] feat: support thrift and pb multi service 3. [[#1268](https://github.com/cloudwego/kitex/pull/1268)] feat(thrift): support frugal fallback for arm @@ -76,6 +76,7 @@ Kitex supports controlling the policies of Timeout, Retry, Circuit Breaker, Limi 10. [[#1211](https://github.com/cloudwego/kitex/pull/1211)] feat(hessian2): support nested struct for hessian2 customized Exception ### Optimize: + 1. [[#1222](https://github.com/cloudwego/kitex/pull/1222)] optimize(frugal): enable frugal by default when the generated code is using slim template 2. [[#1209](https://github.com/cloudwego/kitex/pull/1209)] optimize: split encoder interface to customize meta and payload encoding implementation 3. [[#1206](https://github.com/cloudwego/kitex/pull/1206)] optimize(tool): add IsDir judge in readTemplate and add template register func @@ -86,6 +87,7 @@ Kitex supports controlling the policies of Timeout, Retry, Circuit Breaker, Limi 8. [[#1238](https://github.com/cloudwego/kitex/pull/1238)] optimize(bizerr): support biz status error for streaming mode ### Fix: + 1. [[#1236](https://github.com/cloudwego/kitex/pull/1236)] fix(hessian2): correct code-ref behavior when thrift file is not in project dir 2. [[#1234](https://github.com/cloudwego/kitex/pull/1234)] fix(hessian2): still perform replacement on handler.go when -service is not specified for hessian2 3. [[#1232](https://github.com/cloudwego/kitex/pull/1232)] fix(gRPC): append "h2" to next proto in gRPC tlsConfig to enable protocol negotiation in TLS @@ -95,6 +97,7 @@ Kitex supports controlling the policies of Timeout, Retry, Circuit Breaker, Limi 7. [[#1194](https://github.com/cloudwego/kitex/pull/1194)] fix(retry): always set RespOp && preventive panic to avoid dead loop ### Chore & Tests + 1. [[#1273](https://github.com/cloudwego/kitex/pull/1273)] chore: upgrade netpoll to v0.6.0 2. [[#1263](https://github.com/cloudwego/kitex/pull/1263)] chore: update sonic to v1.11.1 3. [[#1255](https://github.com/cloudwego/kitex/pull/1255)] chore: upgrade netpoll to v0.6.0 pre-release version @@ -104,6 +107,7 @@ Kitex supports controlling the policies of Timeout, Retry, Circuit Breaker, Limi 7. [[#1220](https://github.com/cloudwego/kitex/pull/1220)] test: correct the cachekey in the benchmark test of balancer 8. [[#1196](https://github.com/cloudwego/kitex/pull/1196)] test: add just biz handler message error ------- +--- + **Thanks a lot to those community contributors who submit some pull requests or share your ideas for this version:** -@DMwangnima @jizhuozhi @NX-Official @jieqiboh @Lvnszn @Skyenought +@DMwangnima @jizhuozhi @NX-Official @jieqiboh @Lvnszn @Skyenought diff --git a/content/en/blog/releases/Volo/_index.md b/content/en/blog/releases/Volo/_index.md index f63f18d104..cdfa04f70d 100644 --- a/content/en/blog/releases/Volo/_index.md +++ b/content/en/blog/releases/Volo/_index.md @@ -4,4 +4,3 @@ linkTitle: "Volo" projects: ["Volo"] weight: 4 --- - diff --git a/content/en/blog/releases/Volo/release-v0100.md b/content/en/blog/releases/Volo/release-v0100.md index 2dbe70cb55..0b8a0bb523 100644 --- a/content/en/blog/releases/Volo/release-v0100.md +++ b/content/en/blog/releases/Volo/release-v0100.md @@ -1,6 +1,6 @@ --- -title: 'Volo Release 0.10.0' -linkTitle: 'Release v0.10.0' +title: "Volo Release 0.10.0" +linkTitle: "Release v0.10.0" projects: ["Volo"] date: 2024-04-08 description: > @@ -59,7 +59,6 @@ For middleware that is not aware of user errors, this change should not cause a The error part of the client has changed from `ResponseError` to `ClientError`. Just follow the compiler error message prompts to match the new error variant. - ### IDL Management File volo.yml Format Refactored The structure of the new yml configuration is clearer, easier to maintain, and mainly solves the issue that the old version could not support cross-repository referencing with git. The specific functions and configuration parameters can be seen [here](https://www.cloudwego.io/docs/volo/guide/config). In addition, for the volo-cli command-line tool, we have renamed the previous idl command to repo. @@ -68,7 +67,6 @@ The structure of the new yml configuration is clearer, easier to maintain, and m Install the volo-cli v0.10.0 version and execute the volo migrate command in the volo.yml directory for automatic migration. - ### Change in Default Generated Enum Type In the newly generated code, the default generated Enum type has been changed to a newtype wrapping i32, in order to better support forward compatibility of modifications in the enumeration values of the IDL enum field. @@ -77,7 +75,6 @@ In the newly generated code, the default generated Enum type has been changed to Just modify the enumeration name in the enum field to the corresponding generated name, such as `Foo::Bar` -> `Foo::BAR`. - ## Complete Release Note For the complete Release Note, please refer to: [Volo Changelog](https://github.com/cloudwego/volo/compare/volo-0.9.0...volo-0.10.0) diff --git a/content/en/blog/releases/Volo/release-v020.md b/content/en/blog/releases/Volo/release-v020.md index e8534b3a1b..70272a1e4a 100644 --- a/content/en/blog/releases/Volo/release-v020.md +++ b/content/en/blog/releases/Volo/release-v020.md @@ -8,20 +8,19 @@ description: > ## Feature -* [[#31](https://github.com/cloudwego/volo/pull/31)] Support Windows. -* [[#26](https://github.com/cloudwego/volo/pull/26)] feat: add sd and lb for grpc. -* [[#45](https://github.com/cloudwego/volo/pull/45)] feat(grpc): support uds. -* [[#32](https://github.com/cloudwego/volo/pull/32)] feat: grpc support metainfo. -* [[#30](https://github.com/cloudwego/volo/pull/30)] feat: grpc server add `layer_front()`. -* [[#42](https://github.com/cloudwego/volo/pull/42)] feat(thrift): support multiplex. +- [[#31](https://github.com/cloudwego/volo/pull/31)] Support Windows. +- [[#26](https://github.com/cloudwego/volo/pull/26)] feat: add sd and lb for grpc. +- [[#45](https://github.com/cloudwego/volo/pull/45)] feat(grpc): support uds. +- [[#32](https://github.com/cloudwego/volo/pull/32)] feat: grpc support metainfo. +- [[#30](https://github.com/cloudwego/volo/pull/30)] feat: grpc server add `layer_front()`. +- [[#42](https://github.com/cloudwego/volo/pull/42)] feat(thrift): support multiplex. ## Optimize -* [[#53](https://github.com/cloudwego/volo/pull/53)] fix: `write_field_begin` args. +- [[#53](https://github.com/cloudwego/volo/pull/53)] fix: `write_field_begin` args. ## Fix -* [[#34](https://github.com/cloudwego/volo/pull/34)] fix: connect timeout. -* [[#46](https://github.com/cloudwego/volo/pull/46)] retry IO error only. -* [[#33](https://github.com/cloudwego/volo/pull/33)] fix: grpc middleware error constraints. - +- [[#34](https://github.com/cloudwego/volo/pull/34)] fix: connect timeout. +- [[#46](https://github.com/cloudwego/volo/pull/46)] retry IO error only. +- [[#33](https://github.com/cloudwego/volo/pull/33)] fix: grpc middleware error constraints. diff --git a/content/en/blog/releases/Volo/release-v021.md b/content/en/blog/releases/Volo/release-v021.md index b684e8f548..aaf73dafce 100644 --- a/content/en/blog/releases/Volo/release-v021.md +++ b/content/en/blog/releases/Volo/release-v021.md @@ -6,9 +6,8 @@ date: 2022-10-26 description: > --- -* [[#61](https://github.com/cloudwego/volo/pull/61)] optimize volo-thrift code, remove unnecessary generic parameters. -* [[#63](https://github.com/cloudwego/volo/pull/63)] remove TAIT elision lifetime required after nightly-2022-10-20. -* [[#73](https://github.com/cloudwego/volo/pull/73)] remove useless liftetime parameter in LoadBalance:: InstanceIter. -* [[#65](https://github.com/cloudwego/volo/pull/65)] feat: upgrade clap to 4. -* [[#72](https://github.com/cloudwego/volo/pull/72)] feat: add writev support for volo net conn. - +- [[#61](https://github.com/cloudwego/volo/pull/61)] optimize volo-thrift code, remove unnecessary generic parameters. +- [[#63](https://github.com/cloudwego/volo/pull/63)] remove TAIT elision lifetime required after nightly-2022-10-20. +- [[#73](https://github.com/cloudwego/volo/pull/73)] remove useless liftetime parameter in LoadBalance:: InstanceIter. +- [[#65](https://github.com/cloudwego/volo/pull/65)] feat: upgrade clap to 4. +- [[#72](https://github.com/cloudwego/volo/pull/72)] feat: add writev support for volo net conn. diff --git a/content/en/blog/releases/Volo/release-v032.md b/content/en/blog/releases/Volo/release-v032.md index cbdf40f915..7bc94932cf 100644 --- a/content/en/blog/releases/Volo/release-v032.md +++ b/content/en/blog/releases/Volo/release-v032.md @@ -6,7 +6,7 @@ date: 2023-02-07 description: > --- -In Volo 0.3.2 version, in addition to general bugfixes, there are many improvements. +In Volo 0.3.2 version, in addition to general bugfixes, there are many improvements. In particular, it is very much appreciated that there are community contributors who have brought us important features. ## Trait support for Thrift asynchronous codec @@ -24,7 +24,7 @@ In this release, we updated the versions of metainfo and faststr so that metainf faststr is a string library we modify with reference to smol_str, which implements a zero-cost clone of immutable string. -In addition, FastStr has an incompatible change: previously it implemented `From` for all `AsRef`, but doing so causes the additional memory allocation and copy overhead when using `into` directly. +In addition, FastStr has an incompatible change: previously it implemented `From` for all `AsRef`, but doing so causes the additional memory allocation and copy overhead when using `into` directly. In the new version of 0.2, we only implement `From` for `'static str`、`String`、`Arc`、`Arc`. There's no overhead for these four types to use `into` to convert to FastStr, in a form that avoids memory allocation and copy problems inadvertently brought on by the user. diff --git a/content/en/blog/releases/Volo/release-v041.md b/content/en/blog/releases/Volo/release-v041.md index 1c1aa856e8..8adef05c70 100644 --- a/content/en/blog/releases/Volo/release-v041.md +++ b/content/en/blog/releases/Volo/release-v041.md @@ -1,6 +1,6 @@ --- -title: 'Volo Release 0.4.1' -linkTitle: 'Release v0.4.1' +title: "Volo Release 0.4.1" +linkTitle: "Release v0.4.1" projects: ["Volo"] date: 2023-03-20 description: > diff --git a/content/en/blog/releases/Volo/release-v080.md b/content/en/blog/releases/Volo/release-v080.md index e5e2dd5e82..c6911e9a62 100644 --- a/content/en/blog/releases/Volo/release-v080.md +++ b/content/en/blog/releases/Volo/release-v080.md @@ -1,6 +1,6 @@ --- -title: 'Volo Release 0.8.0' -linkTitle: 'Release v0.8.0' +title: "Volo Release 0.8.0" +linkTitle: "Release v0.8.0" projects: ["Volo"] date: 2023-10-23 description: > @@ -90,6 +90,7 @@ Compared to the previous definition, the type Future associated type is removed, 1. Update Rust compiler to the latest nightly (rustup update) and all dependencies (volo, pilota, motore) to the latest version 2. Run cargo check to see where the errors are, such as "type Future is not a member", "associated type Future not found", etc. We will use the following `Service` as an example: + ```rust impl Service for LogService where @@ -117,10 +118,12 @@ where } } ``` + 3. Remove the line with `type Future` 4. Swap the lifetimes in `fn call<'cx, 's>` and remove the `where` statement below 5. Add `async` before `fn call`, then change `Self::Future<'cx>` to `Result`, and remove the `async move` in the function body 6. The final modified `Service` is as follows: + ```rust impl Service for LogService where diff --git a/content/en/blog/releases/Volo/release-v090.md b/content/en/blog/releases/Volo/release-v090.md index ce0dead8d5..3022923aae 100644 --- a/content/en/blog/releases/Volo/release-v090.md +++ b/content/en/blog/releases/Volo/release-v090.md @@ -1,6 +1,6 @@ --- -title: 'Volo Release 0.9.0' -linkTitle: 'Release v0.9.0' +title: "Volo Release 0.9.0" +linkTitle: "Release v0.9.0" projects: ["Volo"] date: 2024-01-04 description: > @@ -30,7 +30,6 @@ max_frame_size in the volo-thrift client is not actually used due to interface c hyper removed hyper::Body in version 1.0 and introduced hyper::body::Incoming as the requested Body type. In volo-grpc, we have followed up on this change, and we expect that the vast majority of users who have not written their own layers will not be interested. If there are users who use the complete Service generics, just change `Service>` to `Service>`. - ## Complete Release Note For the complete Release Note, please refer to: [Volo Changelog](https://github.com/cloudwego/volo/compare/volo-0.8.0...volo-0.9.0) diff --git a/content/en/blog/releases/_index.md b/content/en/blog/releases/_index.md index 9349f60273..2f084ece65 100644 --- a/content/en/blog/releases/_index.md +++ b/content/en/blog/releases/_index.md @@ -1,9 +1,6 @@ - --- title: "New Releases" projects: [] linkTitle: "Releases" weight: 20 --- - - diff --git a/content/en/community/_index.md b/content/en/community/_index.md index 4d5c1c6a55..2352240f1d 100644 --- a/content/en/community/_index.md +++ b/content/en/community/_index.md @@ -6,6 +6,7 @@ menu: --- {{% blocks/lead color="primary" %}} +
Welcome to the CloudWeGo Community

CloudWeGo is an open source project that anyone in the community can @@ -45,8 +46,8 @@ You may participate in the community through GitHub, or simply by interacting wi If you want to become a Contributor, please read the Contribution Guidelines and the Community Membership Privileges and Guidelines. ## Where to Start? - - If you're looking for a place to start for your first contribution, here's a few things to note. The CloudWeGo project is subdivided into subprojects: + +If you're looking for a place to start for your first contribution, here's a few things to note. The CloudWeGo project is subdivided into subprojects: - Kitex (Kitex & Kitex ecosystem & kitex-contrib) - Hertz (Hertz & Hertz ecosystem & hertz-contrib) diff --git a/content/en/cooperation/_index.md b/content/en/cooperation/_index.md index 1664fa305f..b182c925cc 100644 --- a/content/en/cooperation/_index.md +++ b/content/en/cooperation/_index.md @@ -1,6 +1,6 @@ --- -title: 'Cooperation' -linkTitle: 'Cooperation' +title: "Cooperation" +linkTitle: "Cooperation" menu: main: weight: 40 @@ -26,20 +26,20 @@ Across these industries, there's a shared emphasis on microservices architecture {{< cardpane >}} {{< card header="Huaxing Securities' Kitex Practices in a Hybrid Cloud-Native Architecture" img="/img/usedby/huaxing.png">}} -Huaxing Securities, a CloudWeGo enterprise user, has implemented Kitex framework to enable cross-data center communication within a hybrid cloud-native architecture. +Huaxing Securities, a CloudWeGo enterprise user, has implemented Kitex framework to enable cross-data center communication within a hybrid cloud-native architecture. They've successfully established an observability system tailored for Kitex and conducted practical deployments using Kitex within and across Kubernetes clusters. Learn more {{< /card >}} {{< card header="Kitex Implementation in Semir E-commerce" img="/img/usedby/semir-en.png" >}} -In recent years, the e-commerce industry has seen rapid growth, and Senma E-commerce's online business has experienced significant expansion, encountering demands for high concurrency and performance in its operations. +In recent years, the e-commerce industry has seen rapid growth, and Senma E-commerce's online business has experienced significant expansion, encountering demands for high concurrency and performance in its operations. Senma has officially become an enterprise user of CloudWeGo. By integrating Kitex with Istio, Senma significantly enhanced its capabilities to handle high-concurrency requirements. Learn more {{< /card >}} {{< card header="The Evolution of Feishu's Admin Console Platform" img="/img/usedby/feishu-en.png">}} -Feishu's admin console is an information management platform tailored for enterprise administrators. Through the integration of Kitex's generalized calling capabilities, -Feishu's admin console underwent a platform-level transformation, offering a unified set of standards and common services. +Feishu's admin console is an information management platform tailored for enterprise administrators. Through the integration of Kitex's generalized calling capabilities, +Feishu's admin console underwent a platform-level transformation, offering a unified set of standards and common services. This realization led to the fulfillment of Feishu's vision for the admin console as a unified digital management platform for enterprises. Learn more {{< /card >}} @@ -48,4 +48,3 @@ This realization led to the fulfillment of Feishu's vision for the admin console

- diff --git a/content/en/cooperation/feishu.md b/content/en/cooperation/feishu.md index c473fd02d0..e80ea584e7 100644 --- a/content/en/cooperation/feishu.md +++ b/content/en/cooperation/feishu.md @@ -16,6 +16,7 @@ weight: 3 它通过引入 Kitex 泛化调用对飞书管理后台进行平台化改造,使之变为业务网关,提供一套统一的标准和通用服务,让有管控诉求的套件业务方能快速实现能力集成,并且提供一致的体验。最终实现了飞书管理后台作为企业统一数字化管理平台的愿景。 本文将从三个方面为大家讲解 Kitex 泛化调用在飞书管理后台平台化改造过程中的落地实践: + 1. 架构和挑战,即飞书管理后台单体架构面临的各种挑战; 2. 平台化构想,即飞书管理后台平台化构想和架构升级; 3. 平台化实现,包括微前端技术架构、泛化调用实践和功能扩展。 @@ -83,6 +84,7 @@ Service Mesh 可以看成是 API Gateway 的去中心化实现方式,用来解 ### 新的框架 下面介绍一下我们的新架构,它主要包括: + 1. **Gaia 控制面**。我们增加了 Gaia 平台(基于 Hertz 框架的 Web 服务)来作为我们整个 Admin 的控制系统,负责整体的发布和管控需求,包括接口的生命周期管理、微应用生命周期管理、监控告警、业务线接入、多环境发布等。 2. **前端架构**。前端采用微前端架构,各个业务方通过构建微应用接入 Admin 基座,使用统一封装好的组件库实现前端页面。 3. **后端架构**。后端使用字节通用 BAM 规范,通过泛化调用的方式打通 Admin 和各接入业务方服务,并抽象公共组件以插件的方式进行功能扩展。 @@ -98,6 +100,7 @@ Service Mesh 可以看成是 API Gateway 的去中心化实现方式,用来解 ### Gaia 平台功能 Gaia 平台主要包括以下功能: + 1. **业务线管理**。业务线是实现以业务为维度进行接入 Admin 而提出的概念。通过业务线来聚合业务为维度的所有资源,相关资源包括微应用、菜单、接口、监控等。图中就是业务线管理的菜单页面。 ![feishu6](/img/users/feishu/feishu6.png) @@ -176,16 +179,18 @@ Kitex 和 Hertz 还不能支持接口编排的功能,所以我们通过自定 ## 成果 最后给大家介绍一下我们的演进成果,主要有以下三点: + 1. **业务迭代加速**。Admin 不再关注其他业务线的需求,更加专注于自身的迭代需求。各个业务方发布完全隔离,使得他们不再依赖 Admin,加快了 Admin 整体的业务功能迭代速度。 2. **研发效率提升**。丰富的前后端组件和简单的接入方式,业务方不需要再花费时间熟悉我们的代码仓库,使得业务方接入更加便捷,研发效率大大提升。 3. **工程质量提高**。 - - 其他团队不再向 Admin 仓库提交代码,仓库代码风格趋向统一; - - 去除了大量的业务逻辑,聚焦网关通用逻辑,提高了单测覆盖率; - - Bug 率显著下降,服务 SLA 明显提升。 + - 其他团队不再向 Admin 仓库提交代码,仓库代码风格趋向统一; + - 去除了大量的业务逻辑,聚焦网关通用逻辑,提高了单测覆盖率; + - Bug 率显著下降,服务 SLA 明显提升。 ## 未来规划 我们目前制定了一些未来的发展规划,主要有以下四点: + 1. 开放更多的组件,让接入的业务方聚焦在业务逻辑本身,例如组织管理里面的选人组件,之前需要各个业务方自己内部实现,之后我们会提供一套公共组件,业务方可以直接使用,包括消息中心、任务管理、安全风控、短信邮件等; 2. 完善服务治理和运维能力,包括灰度、降级、限流、精细化大盘等; 3. 建设通用的静态页面托管解决方案,为开发者提供便捷、稳定、高扩展性的静态页面托管服务; diff --git a/content/en/cooperation/huaxingsec.md b/content/en/cooperation/huaxingsec.md index 9a9c139bb0..515aed8857 100644 --- a/content/en/cooperation/huaxingsec.md +++ b/content/en/cooperation/huaxingsec.md @@ -4,6 +4,7 @@ title: "华兴证券:混合云原生架构下的 Kitex 实践" linkTitle: "huaxingsec" weight: 1 --- + ## 案例介绍
@@ -14,12 +15,12 @@ weight: 1 企业用户如何搭建针对 Kitex 的可观测性系统?如何在 K8s 集群下使用 Kitex ? 本文将从以下 4 个方面介绍华兴证券基于 Kitex 在多机房 K8s 集群下的实践经验,包括: + 1. 针对 Kitex 的可观测性系统搭建经验; 2. 服务压力测试中遇到的问题以及解决方案; 3. Kitex 的不同连接类型在 K8s 同集群/跨集群调用下的一些问题和解决方案; 4. 实践中遇到的其他问题以及解决方案; - ## Kitex 的可观性系统搭建 ### 华兴证券 CloudWeGo-Kitex 使用情况 @@ -91,7 +92,7 @@ Tracing 一般只关注调用耗时,然而一条链路中可能出现各种错 - Kitex RPC 返回的 err(Conn Timeout、Read Timeout 等); - IDL 里自定义的业务 Code(111: 用户不存在)。 -2.HTTP + 2.HTTP - 返回的 HTTP 状态码(404、503); - JSON 里的业务 Code(-1: 内部错误)。 @@ -186,6 +187,7 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 ![huaxing18](/img/users/huaxingsec/huaxing18.png) 我们讨论了几种解决方案: + 1. 修改超时配置。然而,交易日的 9:30-9:35 有⼀堆集中交易请求,突发的流量,耗时长了体验不好,可能会影响 APP 收入,我们希望系统性能保持稳定。 2. 进行连接耗时的优化。然而 Kitex 已经使用了 Epoll 来处理创建连接的事件,作为使用方,进一步优化的难度和成本都太大。 3. MaxidleTimeout 参数改成无限大?比如先创建一个足够大的池,然后随着用户请求,池变得越来越大,最终稳定下来。但是每次服务升级之后,这个池就空了,需要慢慢恢复。 @@ -198,6 +200,7 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 ![huaxing20](/img/users/huaxingsec/huaxing20.png) 当时 CloudWeGo 团队针对我们公司建了企业用户交流群,于是我们就向群里的 Kitex 研发提了连接预热的需求。其开发之后提供了连接预热个数的选项。我们也进行了测试。按照 QPS=2000 进行测试, + - WARM_UP_CONN_NUM=0:大约 1s 报错; - WARM_UP_CONN_NUM=100:大约 4s 报错; @@ -209,6 +212,7 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 ![huaxing22](/img/users/huaxingsec/huaxing22.png) 本章小结如下: + - Kitex v0.0.8:域名模式下存在连接池失效问题,v0.1.3 中修复; - Kitex v0.1.3:可进一步通过连接预热功能提高系统性能。 @@ -223,6 +227,7 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 那么,当长连接池数目比较大(比如数千),且上游较多(各种服务、每个都多副本,加起来可能数十个)的情况下,请求高峰时段可能导致上游宿主机的源端口不够用。同集群内跨机器调用走了 vxlan,因此没有这个问题。 解决方案有两类: + - 硬件方案:机器; - 软件方案:对于下游为 Kitex 服务,改用 Mux 模式(这样少量连接就可以处理大量并发的请求)。下游不是 Kitex 框架,因为 Mux 是私有协议,不支持非 Kitex。此时可考虑增加下游服务的 LB 数量,比如每个 LB 上分配多个端口。 @@ -235,31 +240,35 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 上游容器←→ClusterIP(服务的虚拟 IP)←→下游容器 然后我们看看滚动升级流程: + 1. 新容器启动。 2. 新容器 Readiness Check 通过,之后做两件事情: - - 更新 Endpoints 列表:新增新容器,删除旧容器; - - 发送 sigTerm 到旧容器的 1 号进程。 + - 更新 Endpoints 列表:新增新容器,删除旧容器; + - 发送 sigTerm 到旧容器的 1 号进程。 3. 由于更新了 Endpoints 列表,Endpoints 列表发生更新事件,立即回调触发规则更新逻辑(syncProxyRules): - - 添加新容器到 IPVS 的 rs,权重为 1; - - 如果此时 IPVS 的旧容器的中 ActiveConn + InactiveConn > 0(即已有连接还在),旧容器的权重会改成 0,但不会删除 rs。 + - 添加新容器到 IPVS 的 rs,权重为 1; + - 如果此时 IPVS 的旧容器的中 ActiveConn + InactiveConn > 0(即已有连接还在),旧容器的权重会改成 0,但不会删除 rs。 经过步骤 3 之后,已有的连接仍然能够正常工作(因为旧容器 rs 未删),但新建的连接会走到新的容器上(因为旧容器权重 =0)。 在 Service 模式下,上游通过一个固定的 IP: 端口来访问下游,当下游滚动升级的时候,上游看到的地址并未变化,即无法感知到滚动升级。于是,下游即使有优雅退出,但上游并不知道下游开始优雅退出了。之后可能的情况是: + 1. 下游发现连接繁忙,一直没有主动关闭,导致 K8s 配置的优雅升级时间超时,强制 Kill 进程,连接关闭,上游报错。 2. 下游发现连接空闲,主动关闭,然而客户端在关闭之前恰好拿到了连接(且认为可用),然后发起请求,实际上由于连接关闭,发起请求失败报错。 针对此问题,解决方案如下: + 1. 同集群调用:改用 Headless Service 模式(结合 DNSResolver):通过 DNS 列表的增删来感知下游变动; 2. 跨集群调用:借鉴 HTTP2 的 GOAWAY 机制。 ![huaxing23](/img/users/huaxingsec/huaxing23.png) 具体,可采用如下方式: + 1. 收到 sigTerm 的下游直接告诉上游(通过之前建立的 Conn1),同时下游继续处理发来的请求。 2. 上游收到关闭信息之后: - - 新请求通过新建 Conn2 来发; - - 已有的请求仍然通过 Conn1,且处理完了之后,等下游优雅关闭 Conn1。 + - 新请求通过新建 Conn2 来发; + - 已有的请求仍然通过 Conn1,且处理完了之后,等下游优雅关闭 Conn1。 这种方式的优点是同集群跨集群均可使用,缺点是需要 Kitex 框架支持。在我们找 Kitex 团队讨论之后,他们也提供了排期支持本需求。 @@ -268,6 +277,7 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 在 Kitex 团队开发期间,我们测下 Kitex 已有版本对 Headless Service 模式下的滚动升级功能。 测试方案如下: + - Kitex 版本 v0.1.3; - 上下游均为 Mux 模式; - 上游的加了个自定义 DNSResolver,刷新时间为 1s,加日志打印解析结果; @@ -279,6 +289,7 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 ![huaxing24](/img/users/huaxingsec/huaxing24.png) 时序分析如下: + - 旧下游收到 sigTerm,开始 Sleep 10s; - 上游解析到旧下游的 IP,向旧下游发起请求; - DNS 规则更新:旧上游 IP 解析项消失,新下游解析项出现; @@ -288,6 +299,7 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 可见报错时旧下游还未执行退出逻辑,排除旧下游主动关闭连接。请求旧下游期间,且此时解析到新容器 IP(移除了旧容器 IP),报错是因为还没到退出逻辑的时候。因此推测,解析条目变化导致了报错。 根据推测,结合代码(Kitex 客户端部分)分析,可能出现以下并发问题: + - 【协程1】客户端从 Mux池里取出 conn1,即将发起请求(所以没有机会再检查 conn1 状态了); - 【协程2】DNS 更新,移除了 IP,于是 Clean 方法中关闭了 conn1; - 【协程1】客户端用 conn1 发起请求,导致报错 conn closed。 @@ -312,16 +324,17 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 报错:INFO[0050] "{\"code\":-1,\"message\":\"remote or network error: conn closed\"}"。 时序分析为: + 1. 旧下游收到 sigTerm,开始 sleep 10s。 2. IPVS规则变化: - - 新下游 weight=1,ac=0,inac=0; - - 旧下游 weight=0,ac=2,inac=0。 + - 新下游 weight=1,ac=0,inac=0; + - 旧下游 weight=0,ac=2,inac=0。 3. 旧下游 sleep 完成,进入最长为 15s(WithExitWaitTime)的优雅退出。 4. 上游请求报错。 5. 旧下游打印了最后一条日志。 6. IPVS 规则变化: - - 新下游 weight=1,ac=2,inac=0 => ac=2 说明上游新建连接到新容器; - - 旧下游 weight=0,ac=0,inac=2 => inac=2 表示连接关闭。 + - 新下游 weight=1,ac=2,inac=0 => ac=2 说明上游新建连接到新容器; + - 旧下游 weight=0,ac=0,inac=2 => inac=2 表示连接关闭。 7. IPVS 规则变化:旧下游的规则被移除。 ![huaxing27](/img/users/huaxingsec/huaxing27.png) @@ -339,6 +352,7 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 1. 同集群调用:可用 Headless Service 模式,由于 DNS 解析能够得到所有 POD,路由没问题。 2. 跨集群调用:不在同集群内, Headless Service 模式无效,考虑如下方案: + - 方案1:修改服务发现机制。 优点:Kitex 无需改动。 缺点:增加依赖项(服务发现组件)。 @@ -350,6 +364,7 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 缺点:需要 Kitex 支持。 本章小结如下: + - 首先,针对长连接模式分析了跨集群时上游源端口数问题,希望通过多路复用模式解决; - 其次,针对多路复用模式 + K8s Headless Service 模式的优雅升级,实测报错,分析定位了原因,Kitex 研发团队及时解决了相应问题; - 再次,针对多路复用模式 + K8s Service 模式下的优雅升级提出了方案,Kitex 团队完成了实现,迭代了一轮,测试通过; @@ -393,6 +408,7 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 ![huaxing34](/img/users/huaxingsec/huaxing34.png) 我们分析了环境差异: + - 生产环境是专线直连; - 测试环境,因为专线比较昂贵,机房之前通过公网访问,中间有个 NAT 设备。 @@ -402,10 +418,12 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 ![huaxing35](/img/users/huaxingsec/huaxing35.png) 本章小结如下: + - Rpc Timeout:Tontext Tanceled 问题分析和解决; - Rpc Error:Connection Reset 问题分析和解决。 ## 展望 + 未来我们计划把 Gin 更换为更高性能(QPS/时延)的 CloudWeGo-Hertz。因为我们 K 线服务的 Response Size 比较大(~202KiB),更换后 QPS 预计可达原先的 5 倍。 同时,为回馈开源社区,我们打算贡献 Tracing 基础库的代码到 Kitex-contrib/Tracer-opentracing。欢迎持续关注 CloudWeGo 项目,加入社区一起交流。 diff --git a/content/en/cooperation/semir.md b/content/en/cooperation/semir.md index 9900535cf2..157e573712 100644 --- a/content/en/cooperation/semir.md +++ b/content/en/cooperation/semir.md @@ -101,6 +101,7 @@ Istio 基于 Enovy 的 xDS 协议扩展了其控制平面,每个 Pod 中放入 ![semir9](/img/users/semir/semir9.png) 在 Istio 中怎么部署我们的客户端或者服务端呢?有以下两种方式: + 1. 为命名空间开启自动注入:`kubectl label namespace default istio-injection=enabled`。注入之后会产生两个重要的容器,第一个是 Istio-proxy,负责流量拦截和流量代理,比如做流量转发;第二个是 Server-douyin,是负责开发的应用容器。 ![semir10](/img/users/semir/semir10.png) 2. 把 Go 代码打包的镜像部署到集群中: @@ -122,6 +123,7 @@ Istio 基于 Enovy 的 xDS 协议扩展了其控制平面,每个 Pod 中放入 ### Kitex 产生性能优势的原因 CloudWeGo 团队来森马做技术支持时讲到对自研网络库 Netpoll 做了一些性能优化,比如: + - 连接利用率; - 调度延迟优化; - 优化 I/O 调用; diff --git a/content/en/docs/_index.md b/content/en/docs/_index.md index f0d6d396cb..b4dff53e19 100755 --- a/content/en/docs/_index.md +++ b/content/en/docs/_index.md @@ -1,6 +1,6 @@ --- -title: 'Documentation' -linkTitle: 'Documentation' +title: "Documentation" +linkTitle: "Documentation" weight: 1 isFolder: true menu: diff --git a/content/en/docs/cwgo/_index.md b/content/en/docs/cwgo/_index.md index ee3871ae95..1d1425aff3 100644 --- a/content/en/docs/cwgo/_index.md +++ b/content/en/docs/cwgo/_index.md @@ -1,10 +1,10 @@ --- -title: 'Cwgo' -linkTitle: 'Cwgo' +title: "Cwgo" +linkTitle: "Cwgo" weight: 5 Description: Cwgo is a CloudWeGo All in one code generation tool, which integrates the advantages of each component to improve the developer experience. menu: main: weight: 5 - parent: 'Documentation' + parent: "Documentation" --- diff --git a/content/en/docs/cwgo/tutorials/_index.md b/content/en/docs/cwgo/tutorials/_index.md index f5b85fc66c..5b1e7e005b 100644 --- a/content/en/docs/cwgo/tutorials/_index.md +++ b/content/en/docs/cwgo/tutorials/_index.md @@ -3,5 +3,4 @@ title: "Tutorials" linkTitle: "Tutorials" weight: 3 description: > - --- diff --git a/content/en/docs/cwgo/tutorials/api-list/commands.md b/content/en/docs/cwgo/tutorials/api-list/commands.md index 8906cadaf7..e4ce3f243a 100644 --- a/content/en/docs/cwgo/tutorials/api-list/commands.md +++ b/content/en/docs/cwgo/tutorials/api-list/commands.md @@ -48,18 +48,19 @@ The routes are output in json format, in a recursive search order (starting from ```json [ - { - "file_path":"/Users/bytedance/Projects/Personal/Golang/hz-example-thrift/biz/router/hello/example/hello.go", - "start_line":20, - "end_line":20, - "method":"GET", - "route_path":"/hello" - }, - { - "file_path":"/Users/bytedance/Projects/Personal/Golang/hz-example-thrift/router.go", - "start_line":12, - "end_line":12, - "method":"GET", - "route_path":"/ping"} + { + "file_path": "/Users/bytedance/Projects/Personal/Golang/hz-example-thrift/biz/router/hello/example/hello.go", + "start_line": 20, + "end_line": 20, + "method": "GET", + "route_path": "/hello" + }, + { + "file_path": "/Users/bytedance/Projects/Personal/Golang/hz-example-thrift/router.go", + "start_line": 12, + "end_line": 12, + "method": "GET", + "route_path": "/ping" + } ] ``` diff --git a/content/en/docs/cwgo/tutorials/api-list/example.md b/content/en/docs/cwgo/tutorials/api-list/example.md index c50e295496..1e5c48601a 100644 --- a/content/en/docs/cwgo/tutorials/api-list/example.md +++ b/content/en/docs/cwgo/tutorials/api-list/example.md @@ -8,6 +8,7 @@ description: > ## Simple Example Take `hz` tool generated project for example: + > generations please refer to [hz usage(thrift)](/docs/hertz/tutorials/toolkit/usage-thrift) Project Structure: @@ -66,7 +67,6 @@ func Register(r *server.Hertz) { Now execute the `api-list` command in the project root directory - `cwgo api-list` or `cwgo api-list --project_path .` The output is as follows: diff --git a/content/en/docs/cwgo/tutorials/client/command.md b/content/en/docs/cwgo/tutorials/client/command.md index f3eaccb246..b30e0ba9e8 100644 --- a/content/en/docs/cwgo/tutorials/client/command.md +++ b/content/en/docs/cwgo/tutorials/client/command.md @@ -14,10 +14,10 @@ NAME: cwgo client - generate RPC or HTTP client Examples: - # Generate RPC client code + # Generate RPC client code cwgo client --type RPC --idl {{path/to/IDL_file.thrift}} --service {{svc_name}} - - # Generate HTTP client code + + # Generate HTTP client code cwgo client --type HTTP --idl {{path/to/IDL_file.thrift}} --service {{svc_name}} diff --git a/content/en/docs/cwgo/tutorials/client/example_pb.md b/content/en/docs/cwgo/tutorials/client/example_pb.md index b3c7bf47be..e245cb2bea 100644 --- a/content/en/docs/cwgo/tutorials/client/example_pb.md +++ b/content/en/docs/cwgo/tutorials/client/example_pb.md @@ -32,7 +32,7 @@ service HelloService { ### Execute Command ->Note: 项目位于非 GOPATH 下必须指定 gomod,GOPATH 下默认以相对于 GOPATH 的路径作为名字,可不指定 gomod。 +> Note: 项目位于非 GOPATH 下必须指定 gomod,GOPATH 下默认以相对于 GOPATH 的路径作为名字,可不指定 gomod。 ```sh cwgo client --type RPC --idl hello.proto --service hellotest --module {{your_module_name}} -I . @@ -40,7 +40,7 @@ cwgo client --type RPC --idl hello.proto --service hellotest --module {{your_ ### Generate Code -The directory structure and file meaning of the generated code are similar to Thrift, please refer to [Generate Code](/docs/cwgo/tutorials/client/example_thrift/#generate-code). +The directory structure and file meaning of the generated code are similar to Thrift, please refer to [Generate Code](/docs/cwgo/tutorials/client/example_thrift/#generate-code). ## HTTP Client @@ -158,7 +158,7 @@ service HelloService { ### Execute Command ->Note: If the project is located outside of GOPATH, gomod must be specified. GOPATH defaults to a path relative to GOPATH as the name, and gomod may not be specified. +> Note: If the project is located outside of GOPATH, gomod must be specified. GOPATH defaults to a path relative to GOPATH as the name, and gomod may not be specified. ```sh cwgo client --type HTTP --idl hello.proto --service hellotest --module {{your_module_name}} diff --git a/content/en/docs/cwgo/tutorials/client/example_thrift.md b/content/en/docs/cwgo/tutorials/client/example_thrift.md index 38f8c77bad..22f3089a6a 100644 --- a/content/en/docs/cwgo/tutorials/client/example_thrift.md +++ b/content/en/docs/cwgo/tutorials/client/example_thrift.md @@ -30,7 +30,7 @@ service HelloService { ### Execute Command ->Note: If the project is located outside of GOPATH, gomod must be specified. GOPATH defaults to a path relative to GOPATH as the name, and gomod may not be specified. +> Note: If the project is located outside of GOPATH, gomod must be specified. GOPATH defaults to a path relative to GOPATH as the name, and gomod may not be specified. ```sh cwgo client --type RPC --idl hello.thrift --service hellotest --module {{your_module_name}} @@ -88,7 +88,7 @@ service HelloService { ### Execute Command ->Note: If the project is located outside of GOPATH, gomod must be specified. GOPATH defaults to a path relative to GOPATH as the name, and gomod may not be specified. +> Note: If the project is located outside of GOPATH, gomod must be specified. GOPATH defaults to a path relative to GOPATH as the name, and gomod may not be specified. ```sh cwgo client --type HTTP --idl hello.thrift --service hellotest --module {{your_module_name}} diff --git a/content/en/docs/cwgo/tutorials/db/_index.md b/content/en/docs/cwgo/tutorials/db/_index.md index f6483fbb8a..7d58701ef2 100644 --- a/content/en/docs/cwgo/tutorials/db/_index.md +++ b/content/en/docs/cwgo/tutorials/db/_index.md @@ -45,7 +45,7 @@ OPTIONS: ## Specification -```console +````console --dsn value specify database DSN --db_type value specifies the database type (mysql or sqlserver or sqlite or postgres) (default mysql) --out_dir value specifies the output directory path, the default is biz/dao/query @@ -64,4 +64,4 @@ OPTIONS: ```sh cwgo model --db_type mysql --dsn "gorm:gorm@tcp(localhost:9910)/gorm?charset=utf8&parseTime=True&loc=Local" -``` +```` diff --git a/content/en/docs/cwgo/tutorials/doc/commands.md b/content/en/docs/cwgo/tutorials/doc/commands.md index c8425d0c59..1bd08de7e9 100644 --- a/content/en/docs/cwgo/tutorials/doc/commands.md +++ b/content/en/docs/cwgo/tutorials/doc/commands.md @@ -37,24 +37,24 @@ OPTIONS: ## Specification -- idl Specify the main IDL path required for code generation +- idl Specify the main IDL path required for code generation -- module/-mod Specify the go mod name, which must be specified outside of GOPATH. In GOPATH, the default name is the path relative to GOPATH +- module/-mod Specify the go mod name, which must be specified outside of GOPATH. In GOPATH, the default name is the path relative to GOPATH -- out_dir Specify the code output directory, which defaults to the command execution directory +- out_dir Specify the code output directory, which defaults to the command execution directory -- model_dir Specify the model code directory generated by thriftgo or protoc, which defaults to biz/doc/model +- model_dir Specify the model code directory generated by thriftgo or protoc, which defaults to biz/doc/model -- dao_dir Specify the directory for the generated doc curd code, which defaults to biz/doc/dao +- dao_dir Specify the directory for the generated doc curd code, which defaults to biz/doc/dao -- name Specify the document type database name for generating code, default to mongodb, currently only mongodb is supported +- name Specify the document type database name for generating code, default to mongodb, currently only mongodb is supported -- proto_search_path/-I Specify the IDL search directory to use when IDL type is proto +- proto_search_path/-I Specify the IDL search directory to use when IDL type is proto -- thriftgo/-t Parameters passed through to thriftgo +- thriftgo/-t Parameters passed through to thriftgo -- protoc/-p Parameters passed through to protoc +- protoc/-p Parameters passed through to protoc -- verbose Default to false, specified as true will output more detailed log content +- verbose Default to false, specified as true will output more detailed log content -- help/-h help command +- help/-h help command diff --git a/content/en/docs/cwgo/tutorials/doc/example_thrift.md b/content/en/docs/cwgo/tutorials/doc/example_thrift.md index 8456eef351..fee32e2457 100644 --- a/content/en/docs/cwgo/tutorials/doc/example_thrift.md +++ b/content/en/docs/cwgo/tutorials/doc/example_thrift.md @@ -7,7 +7,7 @@ description: > ## Simple Example -### Create video.thrift +### Create video.thrift ```thrift namespace go video @@ -99,5 +99,3 @@ cwgo doc --idl user.thrift --module {your module name} ### Generate Code The directory structure for generating code refers to [layout](/docs/cwgo/tutorials/doc/layout/). - - diff --git a/content/en/docs/cwgo/tutorials/doc/layout.md b/content/en/docs/cwgo/tutorials/doc/layout.md index 73bd7ce30b..3acfc1fe6f 100644 --- a/content/en/docs/cwgo/tutorials/doc/layout.md +++ b/content/en/docs/cwgo/tutorials/doc/layout.md @@ -9,8 +9,8 @@ description: > > biz/doc/dao/{struct name}:Store the mongodb curd code, and the generated location can be modified through --dao dir > -> - {struct name}_repo.go Function interface file -> - {struct name}_repo_mongo.go Interface implementation and specific curd code +> - {struct name}\_repo.go Function interface file +> - {struct name}\_repo_mongo.go Interface implementation and specific curd code > > biz/doc/model:The code generated by thriftgo or protoc, where the go struct corresponding to the Mongodb set is located, can be modified by using --model_dir diff --git a/content/en/docs/cwgo/tutorials/doc/usage_rule.md b/content/en/docs/cwgo/tutorials/doc/usage_rule.md index 3158d28426..d28f9cc9b1 100644 --- a/content/en/docs/cwgo/tutorials/doc/usage_rule.md +++ b/content/en/docs/cwgo/tutorials/doc/usage_rule.md @@ -68,6 +68,7 @@ For specific rules, please refer to [usage rule](#usage-rule). ## Usage Rule The function name adopts a **camel shaped naming**, with the **first letter capitalized**, and the first word must be one of the following: + - **Insert** - **Find** - **Update** @@ -107,7 +108,7 @@ The `Find` operation includes two types: **single entity** and **multiple entiti - **Sorting and pagination operations** | Format | Description | Example | -|----------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------| +| -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- | | **Orderby**{thrift field names 123...} | By default, it is for field ascending. If a field has a descending requirement, add Desc after the field (only applicable to a single field, if there is a requirement for multiple descending fields, Desc needs to be added after each field), for example, OrderbyName (ascending) AgeDesc (descending) **Entering parameters without passing values** | `FindUsernameOrderbyIdUsernameSkipLimitAll`(including two fields "Id" and "Username") | | **Skip** | Skip number of documents **Enter an integer as an input parameter** | `FindUsernameOrderbyIdUsernameSkipLimitAll`(Skip document) | | **Limit** | Limit the number of documents to be queried **Single entity operations are not supported, Enter an integer as an input parameter** | `FindUsernameOrderbyIdUsernameSkipLimitAll`(Limit the number of queried documents) | @@ -122,8 +123,8 @@ The `Find` operation includes two types: **single entity** and **multiple entiti - **Compare Condition**: -| **关键词** | **Description** | **Input param value** | - |:---------------------|:--------------------------------------------------|:------------------------| +| **关键词** | **Description** | **Input param value** | +| :------------------- | :------------------------------------------------ | :---------------------- | | **Equal** | Equal | The value of this field | | **NotEqual** | NotEqual | The value of this field | | **LessThan** | LessThan | The value of this field | @@ -221,7 +222,8 @@ For example: `CollectionUserCollectionInsertMany`, input param: `userCollection ## Keywords ->When naming structure fields, do not include the following keywords: +> When naming structure fields, do not include the following keywords: + - **Insert** - **Find** - **Update** diff --git a/content/en/docs/cwgo/tutorials/server/command.md b/content/en/docs/cwgo/tutorials/server/command.md index dc1a2e46ea..71a66406e7 100644 --- a/content/en/docs/cwgo/tutorials/server/command.md +++ b/content/en/docs/cwgo/tutorials/server/command.md @@ -14,10 +14,10 @@ NAME: cwgo server - generate RPC or HTTP server Examples: - # Generate RPC server code + # Generate RPC server code cwgo server --type RPC --idl {{path/to/IDL_file.thrift}} --service {{svc_name}} - # Generate HTTP server code + # Generate HTTP server code cwgo server --type HTTP --idl {{path/to/IDL_file.thrift}} --service {{svc_name}} diff --git a/content/en/docs/cwgo/tutorials/server/example_pb.md b/content/en/docs/cwgo/tutorials/server/example_pb.md index 3afc8f822a..fe3b745128 100644 --- a/content/en/docs/cwgo/tutorials/server/example_pb.md +++ b/content/en/docs/cwgo/tutorials/server/example_pb.md @@ -32,7 +32,7 @@ service HelloService { ### Execute Command ->Note: If the project is located outside of GOPATH, gomod must be specified. GOPATH defaults to a path relative to GOPATH as the name, and gomod may not be specified. +> Note: If the project is located outside of GOPATH, gomod must be specified. GOPATH defaults to a path relative to GOPATH as the name, and gomod may not be specified. ```sh cwgo server --type RPC --idl hello.proto --service hellotest --module {{your_module_name}} -I . @@ -158,7 +158,7 @@ service HelloService { ### Execute Command ->Note: If the project is located outside of GOPATH, gomod must be specified. GOPATH defaults to a path relative to GOPATH as the name, and gomod may not be specified. +> Note: If the project is located outside of GOPATH, gomod must be specified. GOPATH defaults to a path relative to GOPATH as the name, and gomod may not be specified. ```sh cwgo server --type HTTP --idl hello.proto --service hellotest --module {{your_module_name}} diff --git a/content/en/docs/cwgo/tutorials/server/example_thrift.md b/content/en/docs/cwgo/tutorials/server/example_thrift.md index 08a73ab8bf..94a0f453a0 100644 --- a/content/en/docs/cwgo/tutorials/server/example_thrift.md +++ b/content/en/docs/cwgo/tutorials/server/example_thrift.md @@ -28,7 +28,7 @@ service HelloService { ### Execute Command ->Note: If the project is located outside of GOPATH, gomod must be specified. GOPATH defaults to a path relative to GOPATH as the name, and gomod may not be specified. +> Note: If the project is located outside of GOPATH, gomod must be specified. GOPATH defaults to a path relative to GOPATH as the name, and gomod may not be specified. ```sh cwgo server --type RPC --idl hello.thrift --service hellotest --module {{your_module_name}} @@ -66,7 +66,7 @@ service HelloService { ### Execute Command ->Note: If the project is located outside of GOPATH, gomod must be specified. GOPATH defaults to a path relative to GOPATH as the name, and gomod may not be specified. +> Note: If the project is located outside of GOPATH, gomod must be specified. GOPATH defaults to a path relative to GOPATH as the name, and gomod may not be specified. ```sh cwgo server --type HTTP --idl hello.thrift --service hellotest --module {{your_module_name}} diff --git a/content/en/docs/hertz/_index.md b/content/en/docs/hertz/_index.md index b215dbc9b1..3370204f39 100644 --- a/content/en/docs/hertz/_index.md +++ b/content/en/docs/hertz/_index.md @@ -1,10 +1,10 @@ --- -title: 'Hertz' -linkTitle: 'Hertz' +title: "Hertz" +linkTitle: "Hertz" weight: 2 Description: Hertz [həːts] is a high-performance, high-usability, extensible HTTP framework for Go. It's designed to make it easy for developers to build microservices. menu: main: weight: 2 - parent: 'Documentation' + parent: "Documentation" --- diff --git a/content/en/docs/hertz/faq/_index.md b/content/en/docs/hertz/faq/_index.md index 5131a524dc..6bf12d3629 100644 --- a/content/en/docs/hertz/faq/_index.md +++ b/content/en/docs/hertz/faq/_index.md @@ -2,7 +2,13 @@ title: "FAQ" linkTitle: "FAQ" weight: 4 -keywords: ["Memory Usage", "Common Error Code", "Context Guide", "Numeric Precision Problem"] +keywords: + [ + "Memory Usage", + "Common Error Code", + "Context Guide", + "Numeric Precision Problem", + ] description: "Hertz FAQ." --- @@ -77,7 +83,7 @@ In addition, Hertz also provides the `ctx.Copy()` interface to make it easier fo ```javascript var s = '{"x":6855337641038665531}'; -var obj = JSON. parse(s); +var obj = JSON.parse(s); alert(obj.x); // Output 6855337641038666000 @@ -125,7 +131,7 @@ package main import ( "context" "encoding/json" - + "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/cloudwego/hertz/pkg/common/utils" @@ -138,7 +144,7 @@ type User struct { func main() { h := server.Default() - + h.GET("/hello", func(ctx context.Context, c *app.RequestContext) { var u User err := json.Unmarshal([]byte(`{"id":6855337641038665531}`), &u) @@ -147,7 +153,7 @@ func main() { } c.JSON(consts.StatusOK, u) }) - + h.Spin() } ``` diff --git a/content/en/docs/hertz/getting-started/_index.md b/content/en/docs/hertz/getting-started/_index.md index 36e8cd538c..31bf7e5470 100644 --- a/content/en/docs/hertz/getting-started/_index.md +++ b/content/en/docs/hertz/getting-started/_index.md @@ -2,7 +2,8 @@ title: "Getting Started" linkTitle: "Getting Started" weight: 2 -keywords: ["Hertz", "Development Environment", "Quick Start", "Code Generation Tool"] +keywords: + ["Hertz", "Development Environment", "Quick Start", "Code Generation Tool"] description: "Preparation of Hertz development environment, quick start, and basic use of code generation tool hz." --- @@ -112,15 +113,19 @@ For more information on how to use hz, please refer to: [hz](/zh/docs/hertz/tuto 1. Create the hertz_demo folder in the current directory and go to that directory. 2. Generating code + - Use `hz new` directly, if not currently in `GOPATH`, you need to add `-module` or `-mod` flag to specify a custom module name. See [here](/docs/hertz/tutorials/toolkit/usage/) for details. + - Code generation by specifying an already defined idl file, e.g. `hz new -idl hello.thrift`. + ```thrift namespace go hello.world service HelloService { - string Hello(1: string name); + string Hello(1: string name); } ``` + After execution, a scaffolding of the Hertz project is created in the current directory, with a `ping` interface for testing. 3. Tidy & get dependencies. @@ -167,7 +172,7 @@ If you need to make further updates to the project, you should use the `hz updat namespace go hello.world service HelloService { - string Hello(1: string name); + string Hello(1: string name); string Bye(1: string name); } ``` diff --git a/content/en/docs/hertz/overview/_index.md b/content/en/docs/hertz/overview/_index.md index d87de183d7..df37460f33 100644 --- a/content/en/docs/hertz/overview/_index.md +++ b/content/en/docs/hertz/overview/_index.md @@ -4,21 +4,23 @@ linkTitle: "Overview" weight: 1 keywords: ["HTTP", "Hertz", "Architecture", "Features", "Performance"] description: "This doc covers architecture design, features and performance of Hertz." - --- ## CloudWeGo-Hertz + Hertz [həːts] is a high-performance, high-usability, extensible HTTP framework for Go. It's designed to make it easy for developers to build microservices. -Inspired by other open source frameworks such as [fasthttp](https://github.com/valyala/fasthttp), [gin](https://github.com/gin-gonic/gin), and [echo](https://github.com/labstack/echo), +Inspired by other open source frameworks such as [fasthttp](https://github.com/valyala/fasthttp), [gin](https://github.com/gin-gonic/gin), and [echo](https://github.com/labstack/echo), combined with the unique challenges faced by ByteDance, Hertz has become production-ready and has powered ByteDance's internal services over the years. Today, as Go gains popularity in microservice development, Hertz is the right choice if you are looking for a customisable, high-performance framework to support a variety of use cases. ## Architecture + ![HERTZ](/img/docs/hertz.png) ## Features + ### High usability In modern software engineering, it is agreed that the delivery of high-quality code in a short period of time has become increasingly important in a highly competitive environment. @@ -42,8 +44,8 @@ Please refer to https://github.com/cloudwego/hertz-benchmark for more details ab ### High extensibility -Hertz uses a layered architecture to deliver a "batteries included" experience. Because of its layered design, the framework is highly extensible, while its core functionality remains robust. -Hertz comes with default implementations for many modules, but also allows users to extend them to suit their own needs. At present, only stable features have been released to the open source community. +Hertz uses a layered architecture to deliver a "batteries included" experience. Because of its layered design, the framework is highly extensible, while its core functionality remains robust. +Hertz comes with default implementations for many modules, but also allows users to extend them to suit their own needs. At present, only stable features have been released to the open source community. For further planning, please refer to the [RoadMap](https://github.com/cloudwego/hertz/blob/main/ROADMAP.md). ### Multi-protocol support @@ -61,11 +63,13 @@ Performance testing can only provide a relative reference. In production, there We provide the [hertz-benchmark](https://github.com/cloudwego/hertz-benchmark) project to track and compare the performance of Hertz and other frameworks in different situations for reference. ## Related Projects + - [Netpoll](https://github.com/cloudwego/netpoll): A high-performance network library. Hertz uses it by default. - [Hertz-Contrib](https://github.com/hertz-contrib): A collection of Hertz extensions. - [Example](https://github.com/cloudwego/hertz-examples): A repository to host examples for Hertz. ## Blogs + - [Getting Started with Hertz: Performance Testing Guide](/blog/2023/02/24/getting-started-with-hertz-performance-testing-guide/) - [Hertz, an Ultra Large Scale Enterprise-Level Microservice HTTP Framework, is Now Officially Open Source!](/blog/2022/06/21/hertz-an-ultra-large-scale-enterprise-level-microservice-http-framework-is-now-officially-open-source/) - [ByteDance Practice on Go Network Library](/blog/2020/05/24/bytedance-practices-on-go-network-library/) diff --git a/content/en/docs/hertz/reference/_index.md b/content/en/docs/hertz/reference/_index.md index 693f8de975..a654c86b4c 100644 --- a/content/en/docs/hertz/reference/_index.md +++ b/content/en/docs/hertz/reference/_index.md @@ -4,5 +4,4 @@ linkTitle: "Reference" weight: 5 keywords: ["Configuration instruction", "Version Descriptions"] description: "Hertz related references." - --- diff --git a/content/en/docs/hertz/reference/config.md b/content/en/docs/hertz/reference/config.md index 99e915f31e..ec5358dce2 100644 --- a/content/en/docs/hertz/reference/config.md +++ b/content/en/docs/hertz/reference/config.md @@ -4,7 +4,6 @@ linkTitle: "Configuration instruction" weight: 1 keywords: ["Configuration instruction"] description: "Hertz configuration instruction." - --- ## Server @@ -22,51 +21,51 @@ func main() { } ``` -| Configuration Name | Type | Description | -| :---- |:-------------------------------------------------------------| :---- | -| WithTransport | network.NewTransporter | Replace the transport. Default:netpoll.NewTransporter | -| WithHostPorts | string | Specify the listening address and port | -| WithKeepAliveTimeout | time.Duration | Set the keep-alive time of tcp persistent connection, generally no need to modify it, you should more pay attention to idleTimeout rather than modifying it. Default: 1min. | -| WithReadTimeout | time.Duration | The timeout of data reading. Default:3min. | -| WithIdleTimeout | time.Duration | The free timeout of the request link for persistent connection. Default: 3min. | -| WithMaxRequestBodySize | int | Max body size of a request. Default: 4M (the corresponding value of 4M is 4\*1024\*1024). | -| WithRedirectTrailingSlash | bool | Whether to redirect with the / which is at the end of the router automatically. For example: If there is only /foo/ in the router, /foo will be redirected to /foo/. And if there is only /foo in the router, /foo/ will be redirected to /foo. Default: true. | -| WithRemoveExtraSlash | bool | RemoveExtraSlash makes the parameter still valid when it contains an extra /. For example, if WithRemoveExtraSlash is true user//xiaoming can match the user/:name router. Default: false. | -| WithUnescapePathValues | bool | If true, the request path will be escaped automatically (eg. '%2F' -> '/'). If UseRawPath is false (the default), UnescapePathValues is true, because URI().Path() will be used and it is already escaped. To set WithUnescapePathValues to false, you need to set WithUseRawPath to true. Default (true). | -| WithUseRawPath | bool | If true, the original path will be used to match the route. Default: false. | -| WithHandleMethodNotAllowed | bool | If true when the current path cannot match any method, the server will check whether other methods are registered with the route of the current path, and if exist other methods, it will respond "Method Not Allowed" and return the status code 405; if not, it will use the handler of NotFound to handle it. Default: false. | -| WithDisablePreParseMultipartForm | bool | If true, the multipart form will not be preprocessed. The body can be obtained via ctx.Request.Body() and then can be processed by user. Default: false. | -| WithStreamBody | bool | If true, the body will be handled by stream processing. Default: false. | -| WithNetwork | string | Set the network protocol, optional: tcp,udp,unix(unix domain socket). Default: tcp. | -| ContinueHandler | func(header *RequestHeader) bool | Call the ContinueHandler after receiving the Expect 100 Continue header. With ContinueHandler, the server can decide whether to read the potentially large request body based on the header. | -| PanicHandler | HandlerFunc | Handle panic used to generate error pages and return error code 500. | -| NotFound | HandlerFunc | The handler to be called when the route does not match. | -| WithExitWaitTime | time.Duration | Set the graceful exit time. the Server will stop connection establishment for new requests and set the Connection: Close header for each request after closing. When the set time is reached, Server will to be closed. the Server can be closed early when all connections have been closed. Default: 5s. | -| WithTLS | tls.Config | Configuring server tls capabilities. | -| WithListenConfig | net.ListenConfig | Set the listener configuration. Can be used to set whether to allow reuse ports, etc.| -| WithALPN | bool | Whether to enable ALPN. Default: false. | -| WithTracer | tracer.Tracer | Inject tracer implementation, if not inject Tracer. Default: close. | -| WithTraceLevel | stats.Level | Set trace level, Default: LevelDetailed. | -| WithWriteTimeout | time.Duration | The timeout of data writing. Default:infinite.| -| WithRedirectFixedPath | bool | If enabled, if the current request path does not match, the server will try to repair the request path and re-match, if the match is successful and the request is a GET request, it will return status code 301 for redirect, other requests will return 308 for redirect. Disabled by default | -| WithBasePath | string | Set the base path, which must be prefixed and suffixed with `/`. The default is `/` | -| WithMaxKeepBodySize | int | Sets the maximum size of the request body and response body to be retained during reclaim. Unit: Byte. Default value: 4 * 1024 * 1024 | -| WithGetOnly | bool | If enabled, only GET requests are accepted. Disabled by default | -| WithKeepAlive | bool | If enabled, use HTTP keepalive. Enabled by default | -| WithAltTransport | network.NewTransporter | Set up the alternate transport. Default value: netpoll.NewTransporter | -| WithH2C | bool | Sets whether H2C is enabled. Disabled by default | -| WithReadBufferSize | int | Set the read buffer size while limiting the HTTP header size. Default value: 4 * 1024 | -| WithRegistry | registry.Registry, *registry.Info | Setup registry configuration, service registration information. Default value: registry.NoopRegistry, nil | -| WithAutoReloadRender | bool, time.Duration | Set up the automatic reload rendering configuration. Default value: false, 0 | -| WithDisablePrintRoute | bool | Sets whether debugPrintRoute is disabled. Default disable | -| WithOnAccept | func(conn net.Conn) context.Context | Set the callback function when a new connection is accepted but cannot receive data in netpoll. In go net, it will be called before converting tls connection. Default value: nil | -| WithOnConnect | func(ctx context.Context, conn network.Conn) context.Context | Set the onConnect function. It can received data from connection in netpoll. In go net, it will be called after converting tls connection. Default value: nil | -| WithDisableHeaderNamesNormalizing| bool |Sets whether or not to disable Request and Response Header name normalization (capitalization of the first letter and the first letter after a dash)| +| Configuration Name | Type | Description | +| :-------------------------------- | :----------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| WithTransport | network.NewTransporter | Replace the transport. Default:netpoll.NewTransporter | +| WithHostPorts | string | Specify the listening address and port | +| WithKeepAliveTimeout | time.Duration | Set the keep-alive time of tcp persistent connection, generally no need to modify it, you should more pay attention to idleTimeout rather than modifying it. Default: 1min. | +| WithReadTimeout | time.Duration | The timeout of data reading. Default:3min. | +| WithIdleTimeout | time.Duration | The free timeout of the request link for persistent connection. Default: 3min. | +| WithMaxRequestBodySize | int | Max body size of a request. Default: 4M (the corresponding value of 4M is 4\*1024\*1024). | +| WithRedirectTrailingSlash | bool | Whether to redirect with the / which is at the end of the router automatically. For example: If there is only /foo/ in the router, /foo will be redirected to /foo/. And if there is only /foo in the router, /foo/ will be redirected to /foo. Default: true. | +| WithRemoveExtraSlash | bool | RemoveExtraSlash makes the parameter still valid when it contains an extra /. For example, if WithRemoveExtraSlash is true user//xiaoming can match the user/:name router. Default: false. | +| WithUnescapePathValues | bool | If true, the request path will be escaped automatically (eg. '%2F' -> '/'). If UseRawPath is false (the default), UnescapePathValues is true, because URI().Path() will be used and it is already escaped. To set WithUnescapePathValues to false, you need to set WithUseRawPath to true. Default (true). | +| WithUseRawPath | bool | If true, the original path will be used to match the route. Default: false. | +| WithHandleMethodNotAllowed | bool | If true when the current path cannot match any method, the server will check whether other methods are registered with the route of the current path, and if exist other methods, it will respond "Method Not Allowed" and return the status code 405; if not, it will use the handler of NotFound to handle it. Default: false. | +| WithDisablePreParseMultipartForm | bool | If true, the multipart form will not be preprocessed. The body can be obtained via ctx.Request.Body() and then can be processed by user. Default: false. | +| WithStreamBody | bool | If true, the body will be handled by stream processing. Default: false. | +| WithNetwork | string | Set the network protocol, optional: tcp,udp,unix(unix domain socket). Default: tcp. | +| ContinueHandler | func(header \*RequestHeader) bool | Call the ContinueHandler after receiving the Expect 100 Continue header. With ContinueHandler, the server can decide whether to read the potentially large request body based on the header. | +| PanicHandler | HandlerFunc | Handle panic used to generate error pages and return error code 500. | +| NotFound | HandlerFunc | The handler to be called when the route does not match. | +| WithExitWaitTime | time.Duration | Set the graceful exit time. the Server will stop connection establishment for new requests and set the Connection: Close header for each request after closing. When the set time is reached, Server will to be closed. the Server can be closed early when all connections have been closed. Default: 5s. | +| WithTLS | tls.Config | Configuring server tls capabilities. | +| WithListenConfig | net.ListenConfig | Set the listener configuration. Can be used to set whether to allow reuse ports, etc. | +| WithALPN | bool | Whether to enable ALPN. Default: false. | +| WithTracer | tracer.Tracer | Inject tracer implementation, if not inject Tracer. Default: close. | +| WithTraceLevel | stats.Level | Set trace level, Default: LevelDetailed. | +| WithWriteTimeout | time.Duration | The timeout of data writing. Default:infinite. | +| WithRedirectFixedPath | bool | If enabled, if the current request path does not match, the server will try to repair the request path and re-match, if the match is successful and the request is a GET request, it will return status code 301 for redirect, other requests will return 308 for redirect. Disabled by default | +| WithBasePath | string | Set the base path, which must be prefixed and suffixed with `/`. The default is `/` | +| WithMaxKeepBodySize | int | Sets the maximum size of the request body and response body to be retained during reclaim. Unit: Byte. Default value: 4 _ 1024 _ 1024 | +| WithGetOnly | bool | If enabled, only GET requests are accepted. Disabled by default | +| WithKeepAlive | bool | If enabled, use HTTP keepalive. Enabled by default | +| WithAltTransport | network.NewTransporter | Set up the alternate transport. Default value: netpoll.NewTransporter | +| WithH2C | bool | Sets whether H2C is enabled. Disabled by default | +| WithReadBufferSize | int | Set the read buffer size while limiting the HTTP header size. Default value: 4 \* 1024 | +| WithRegistry | registry.Registry, \*registry.Info | Setup registry configuration, service registration information. Default value: registry.NoopRegistry, nil | +| WithAutoReloadRender | bool, time.Duration | Set up the automatic reload rendering configuration. Default value: false, 0 | +| WithDisablePrintRoute | bool | Sets whether debugPrintRoute is disabled. Default disable | +| WithOnAccept | func(conn net.Conn) context.Context | Set the callback function when a new connection is accepted but cannot receive data in netpoll. In go net, it will be called before converting tls connection. Default value: nil | +| WithOnConnect | func(ctx context.Context, conn network.Conn) context.Context | Set the onConnect function. It can received data from connection in netpoll. In go net, it will be called after converting tls connection. Default value: nil | +| WithDisableHeaderNamesNormalizing | bool | Sets whether or not to disable Request and Response Header name normalization (capitalization of the first letter and the first letter after a dash) | Server Connection limitation: -* If you are using the standard network library, there is no such restriction. -* If netpoll is used, the maximum number of connections is 10000 (this is +- If you are using the standard network library, there is no such restriction. +- If netpoll is used, the maximum number of connections is 10000 (this is the [gopool](https://github.com/bytedance/gopkg/blob/b9c1c36b51a6837cef4c2223e11522e3a647460c/util/gopool/gopool.go#L46)) used at the bottom of netpoll. Yes, the modification method is also very simple, just call the function provided by gopool: `gopool.SetCap(xxx)` (you can call it once in main.go). @@ -86,20 +85,20 @@ func main() { } ``` -| Configuration Name | Type | Description | -| :---- | :---- |:----| -| WithDialTimeout | time.Duration | Connection establishment timeout. Default: 1s. | -| WithMaxConnsPerHost | int | Set the maximum number of connections for every host. Default: 512. | -| WithMaxIdleConnDuration | time.Duration | Set the idle connection timeout, which will close the connection after the timeout Default: 10s. | -| WithMaxConnDuration | time.Duration | Set the maximum keep-alive time of the connection, when the timeout expired, the connection will be closed after the current request is completed. Default: infinite. | -| WithMaxConnWaitTimeout | time.Duration | Set the maximum time to wait for an idle connection. Default: no wait. | -| WithKeepAlive | bool | Whether to use persistent connection. Default: true. | -| WithRetryConfig | ...retry.Option | Set the retry config of client. Hertz version >= v0.4.0. | -| ~~WithMaxIdempotentCallAttempts~~ | int | Set the maximum number of calls. If a call fails, it will be retried. Default: 1 (That is no retry). v0.4.0 is obsolete. Only available before v0.4.0. It is recommended to upgrade Hertz version >= v0.4.0 and use WithRetryConfig instead. | -| WithClientReadTimeout | time.Duration | Set the maximum time to read the response. Default: infinite. | -| WithTLSConfig | *tls.Config | Set the client's TLS config for mutual TLS authentication. | -| WithDialer | network.Dialer | Set the network library used by the client. Default: netpoll. | -| WithResponseBodyStream | bool | Set whether to use stream processing. Default: false. | -| WithDialFunc | client.DialFunc | Set Dial Function. | -| WithWriteTimeout | time.Duration | The timeout of data writing. Default:infinite. | -| WithHostClientConfigHook | func(hc interface{}) error | Set the function hook for re-configure the host client. The function needs to assert the parameter hc as the required struct, such as http1.HostClient, and then perform specific processing. | +| Configuration Name | Type | Description | +| :-------------------------------- | :------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| WithDialTimeout | time.Duration | Connection establishment timeout. Default: 1s. | +| WithMaxConnsPerHost | int | Set the maximum number of connections for every host. Default: 512. | +| WithMaxIdleConnDuration | time.Duration | Set the idle connection timeout, which will close the connection after the timeout Default: 10s. | +| WithMaxConnDuration | time.Duration | Set the maximum keep-alive time of the connection, when the timeout expired, the connection will be closed after the current request is completed. Default: infinite. | +| WithMaxConnWaitTimeout | time.Duration | Set the maximum time to wait for an idle connection. Default: no wait. | +| WithKeepAlive | bool | Whether to use persistent connection. Default: true. | +| WithRetryConfig | ...retry.Option | Set the retry config of client. Hertz version >= v0.4.0. | +| ~~WithMaxIdempotentCallAttempts~~ | int | Set the maximum number of calls. If a call fails, it will be retried. Default: 1 (That is no retry). v0.4.0 is obsolete. Only available before v0.4.0. It is recommended to upgrade Hertz version >= v0.4.0 and use WithRetryConfig instead. | +| WithClientReadTimeout | time.Duration | Set the maximum time to read the response. Default: infinite. | +| WithTLSConfig | \*tls.Config | Set the client's TLS config for mutual TLS authentication. | +| WithDialer | network.Dialer | Set the network library used by the client. Default: netpoll. | +| WithResponseBodyStream | bool | Set whether to use stream processing. Default: false. | +| WithDialFunc | client.DialFunc | Set Dial Function. | +| WithWriteTimeout | time.Duration | The timeout of data writing. Default:infinite. | +| WithHostClientConfigHook | func(hc interface{}) error | Set the function hook for re-configure the host client. The function needs to assert the parameter hc as the required struct, such as http1.HostClient, and then perform specific processing. | diff --git a/content/en/docs/hertz/reference/version.md b/content/en/docs/hertz/reference/version.md index c53ea0b76b..445b2fca07 100644 --- a/content/en/docs/hertz/reference/version.md +++ b/content/en/docs/hertz/reference/version.md @@ -4,7 +4,6 @@ linkTitle: "Version Descriptions" weight: 2 keywords: ["Version Description"] description: "Hertz version description." - --- Hertz complies with the [Semantic Version 2.0.0](https://semver.org/lang/zh-CN/) release version. diff --git a/content/en/docs/hertz/tutorials/_index.md b/content/en/docs/hertz/tutorials/_index.md index 2b50a1cebe..8d7425fb05 100644 --- a/content/en/docs/hertz/tutorials/_index.md +++ b/content/en/docs/hertz/tutorials/_index.md @@ -2,7 +2,16 @@ title: "Tutorials" linkTitle: "Tutorials" weight: 3 -keywords: ["Tutorials", "Example code", "Basic Feature", "Observability", "Service Governance", "Framework Extension", "hz Code Generation", "Migration to Hertz"] +keywords: + [ + "Tutorials", + "Example code", + "Basic Feature", + "Observability", + "Service Governance", + "Framework Extension", + "hz Code Generation", + "Migration to Hertz", + ] description: "Hertz tutorials, including example code, basic feature, observability, service governance, framework extension, hz code generation, and migration to Hertz." - --- diff --git a/content/en/docs/hertz/tutorials/basic-feature/_index.md b/content/en/docs/hertz/tutorials/basic-feature/_index.md index 01567571a1..0812a62a9c 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/_index.md +++ b/content/en/docs/hertz/tutorials/basic-feature/_index.md @@ -2,7 +2,27 @@ title: "Basic Feature" linkTitle: "Basic Feature" weight: 2 -keywords: ["Engine", "Route", "Client", "Network Lib", "RequestContext", "Middleware", "Protocol", "Binding and validate", "Stream", "Error Handle", "Graceful Shutdown", "Forward Proxy and Reverse Proxy", "Retry", "Hooks", "Unit Test", "Adaptor", "Constants", "Render", "JSON Marshal Library"] +keywords: + [ + "Engine", + "Route", + "Client", + "Network Lib", + "RequestContext", + "Middleware", + "Protocol", + "Binding and validate", + "Stream", + "Error Handle", + "Graceful Shutdown", + "Forward Proxy and Reverse Proxy", + "Retry", + "Hooks", + "Unit Test", + "Adaptor", + "Constants", + "Render", + "JSON Marshal Library", + ] description: "Basic feature of Hertz." - --- diff --git a/content/en/docs/hertz/tutorials/basic-feature/adaptor.md b/content/en/docs/hertz/tutorials/basic-feature/adaptor.md index d1680c51e2..24165112c7 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/adaptor.md +++ b/content/en/docs/hertz/tutorials/basic-feature/adaptor.md @@ -4,7 +4,6 @@ date: 2023-01-11 weight: 16 keywords: ["Adaptor", "http.Request", "http.ResponseWriter", "net/http"] description: "Hertz provides access and related methods to Go standard library `http.Request` and `http.ResponseWriter`." - --- Hertz provides access and related methods to Go standard library `http.Request` and `http.ResponseWriter`, it is easy for users to integrate `net/http` to develop application. @@ -61,14 +60,14 @@ func main() { ## http.Request | Function | Function Signature | Description | -|--------------------|-----------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ------------------ | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | GetCompatRequest | `func GetCompatRequest(req *protocol.Request) (*http.Request, error)` | Build and fetch Go standard library `http.Request` from Hertz `protocol.Request` | | CopyToHertzRequest | `func CopyToHertzRequest(req *http.Request, hreq *protocol.Request)` | Copy the `URI`, `Host`, `Method`, `Protocol`, `Header` of Go standard library `http.Request` to Hertz `protocol.Request`, The `Body` field will be adapted by sharing `Reader` | ## http.ResponseWriter | Function / Struct | Function Signature | Description | -|-------------------------|-----------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------| +| ----------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | GetCompatResponseWriter | `func GetCompatResponseWriter(resp *protocol.Response) http.ResponseWriter` | Build and fetch Go standard library `http.ResponseWriter` from Hertz `protocol.Response` | | compatResponse | / | `compatResponse` implements the `http.ResponseWriter` interface and has adaptations to `Header`, `Write` and `WriteHeader` functions | @@ -77,7 +76,7 @@ func main() { Hertz pprof middleware provides adaptation methods for the Go standard library `http.Handler` and `http.HandlerFunc`, it is easy for users to adapt to Hertz `app.HandlerFunc` for development. | Function | Function Signature | Description | -|-------------------------|--------------------------------------------------------------------|-----------------------------------------------------------------------------------| +| ----------------------- | ------------------------------------------------------------------ | --------------------------------------------------------------------------------- | | NewHertzHTTPHandlerFunc | `func NewHertzHTTPHandlerFunc(h http.HandlerFunc) app.HandlerFunc` | Used to convert Go standard library `http.HandlerFunc` to Hertz `app.HandlerFunc` | | NewHertzHTTPHandler | `func NewHertzHTTPHandler(h http.Handler) app.HandlerFunc` | Used to convert Go standard library `http.Handler` to Hertz `app.HandlerFunc` | diff --git a/content/en/docs/hertz/tutorials/basic-feature/binding-and-validate.md b/content/en/docs/hertz/tutorials/basic-feature/binding-and-validate.md index 848fe4edfa..57bfef5e7c 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/binding-and-validate.md +++ b/content/en/docs/hertz/tutorials/basic-feature/binding-and-validate.md @@ -2,7 +2,8 @@ title: "Binding and validate" date: 2022-06-21 weight: 8 -keywords: ["Binding and validate", "go-tagexpr", "tag", "Parameter binding precedence"] +keywords: + ["Binding and validate", "go-tagexpr", "tag", "Parameter binding precedence"] description: "The parameter binding and validation related functions and usage supported by Hertz." --- @@ -40,11 +41,11 @@ func main() { ``` ### APIs -> + > hertz version >= v0.7.0 | API | Description | -|:----------------------|:-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| :-------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ctx.BindAndValidate | Use the following go-tag for parameter binding, and do a parameter validation after successful binding (if there is a validation tag) | | ctx.Bind | Same as `BindAndValidate` but without parameter validation | | ctx.BindQuery | Bind all Query parameters, which is equivalent to declaring a `query` tag for each field, for scenarios where no tag is written | @@ -65,7 +66,7 @@ When generating code without IDL, if no tags are added to the field, it will tra If [api-annotations](/docs/hertz/tutorials/toolkit/annotation/#supported-api-annotations) are not added when generating code through IDL, the fields will default to adding `form`, `JSON`, and `query` tags. Adding [api-annotations](/docs/hertz/tutorials/toolkit/annotation/#supported-api-annotations) will add the corresponding required tags for the fields. | go tag | description | -|----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | path | This tag is used to bind parameters on url like `:param` or `*param`. For example: if we defined route is: `/v:version/example`, you can specify the path parameter as the route parameter: `path:"version"`. In this case if url is http://127.0.0.1:8888/v1/ , you can bind the path parameter "1". | | form | This tag is used to bind the key-value of the form in request body which content-type is `multipart/form-data` or `application/x-www-form-urlencoded` | | query | This tag is used to bind query parameter in request | @@ -74,7 +75,7 @@ If [api-annotations](/docs/hertz/tutorials/toolkit/annotation/#supported-api-ann | json | This tag is used to bind json parameters in the request body which content-type is `application/json` | | raw_body | This tag is used to bind the original body (bytes type) of the request, and parameters can be bound even if the bound field name is not specified. (Note: raw_body has the lowest binding priority. When multiple tags are specified, once other tags successfully bind parameters, the body content will not be bound) | | vd | `vd` short for validator, [The grammar of validation parameter](https://github.com/bytedance/go-tagexpr/tree/master/validator) | -| default | Set default value | +| default | Set default value | ### Parameter Validation @@ -112,7 +113,7 @@ path > form > query > cookie > header > json > raw_body You can specify a parameter as required with keyword `required` in tag. Both `Bind` and `BindAndValidate` returns error when a required parameter is missing. When multiple tags contain the`required` keyword, parameter with be bound in order of precedence defined above. If none of the tags bind, an error will be returned. -``` go +```go type TagRequiredReq struct { // when field hertz is missing in JSON, a required error will be return: binding: expr_path=hertz, cause=missing required parameter Hertz string `json:"hertz,required"` @@ -122,12 +123,12 @@ type TagRequiredReq struct { ``` ## Common config -> + > hertz has refactored `parameter binding` and `checksum` in version v0.7.0, which changes the behaviour of the configurations, as described below
respectively. > If you still want to use the previous binder, it is now implemented under [hertz-contrib/binding](https://github.com/hertz-contrib/binding) and can be introduced via a custom binder. ### Customise binder -> + > hertz version >= v0.7.0 support You need to implement the Binder interface and inject it into the hertz engine in a configurable way. @@ -201,10 +202,10 @@ func (m *mockBinder) BindProtobuf(request *protocol.Request, i interface{}) erro Currently expanded binders: -* bytedance/go-tagexpr: https://github.com/hertz-contrib/binding/tree/main/go_tagexpr (binding library used before refactoring) +- bytedance/go-tagexpr: https://github.com/hertz-contrib/binding/tree/main/go_tagexpr (binding library used before refactoring) ### Custom validator -> + > Supported by hertz version >= v0.7.0. You need to implement the Validator interface and inject it into the hertz engine in a configurable way. @@ -246,13 +247,14 @@ func (m *mockValidator) ValidateTag() string { Currently expanded validators: -* go-playground/validator: https://github.com/hertz-contrib/binding/tree/main/go_playground +- go-playground/validator: https://github.com/hertz-contrib/binding/tree/main/go_playground ### Customize the error of binding and validation When an error occurs in the binding parameter and the parameter validation fails, user can customize the Error([demo](https://github.com/cloudwego/hertz-examples/tree/main/binding/custom_error))For example: The user can customise the content of the Error in case of binding parameter errors and parameter validation failures, using the following method:
**hertz version >= v0.7.0** + > Custom bind errors are not supported at this time. Custom validate error: @@ -285,7 +287,7 @@ func main() { FailField: "[validateFailField]: " + failField, Msg: "[validateErrMsg]: " + msg, } - + return &err }) h := server.New(server.WithValidateConfig(validateConfig)) @@ -331,7 +333,7 @@ func init() { FailField: "[bindFailField]: " + failField, Msg: "[bindErrMsg]: " + msg, } - + return &err } @@ -401,7 +403,7 @@ type TestBind struct { func main() { bindConfig := &binding.BindConfig{} - // After v0.7.0 refactoring, on the basis of the original increase in the request content and routing parameters, + // After v0.7.0 refactoring, on the basis of the original increase in the request content and routing parameters, // which can be more flexible for the user to customise the type of parsing // Note: Only after a tag is successfully matched will the custom logic go through. bindConfig.MustRegTypeUnmarshal(reflect.TypeOf(Nested{}), func(req *protocol.Request, params param.Params, text string) (reflect.Value, error) { @@ -416,7 +418,7 @@ func main() { return reflect.ValueOf(val), nil }) h := server.New(server.WithBindConfig(bindConfig)) - + ... h.Spin() } @@ -570,10 +572,10 @@ import "github.com/cloudwego/hertz/pkg/app/server/binding" func init() { // Use the standard library as a JSON deserialisation tool binding.UseStdJSONUnmarshaler() - + // Use GJSON as the JSON deserialisation tool. binding.UseGJSONUnmarshaler() - + // Use third-party JSON libraries as JSON deserialisers. binding.UseThirdPartyJSONUnmarshaler() } @@ -614,10 +616,10 @@ Reason: `string` and `int` conversion is not supported by default Solution: -* We are recommended to use the `string` tag of the standard package json. For example: +- We are recommended to use the `string` tag of the standard package json. For example: ```go A int `json:"A, string"` ``` -* Configure other json libraries that support this operation. +- Configure other json libraries that support this operation. diff --git a/content/en/docs/hertz/tutorials/basic-feature/client.md b/content/en/docs/hertz/tutorials/basic-feature/client.md index def87f99d9..4f7565c883 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/client.md +++ b/content/en/docs/hertz/tutorials/basic-feature/client.md @@ -2,12 +2,18 @@ title: "Client" date: 2023-07-25 weight: 3 -keywords: ["Client Config", "Send Request", "Request Timeout", "Streaming", "Middleware", "Service Discovery"] +keywords: + [ + "Client Config", + "Send Request", + "Request Timeout", + "Streaming", + "Middleware", + "Service Discovery", + ] description: "Hertz client related functions." --- - - ## Quick Start ```go @@ -16,7 +22,7 @@ package main import ( "context" "fmt" - + "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/client" "github.com/cloudwego/hertz/pkg/app/server" @@ -46,27 +52,27 @@ func main() { ## Client Config -| **Option** | **Default** | **Description** | -|-----------------------------------| -------------- |-----------------| -| WithDialTimeout | 1s | dial timeout. | -| WithMaxConnsPerHost | 512 | maximum number of connections per host which may be established. | -| WithMaxIdleConnDuration | 10s | max idle connection duration, idle keep-alive connections are closed after this duration. | -| WithMaxConnDuration | 0s | max connection duration, keep-alive connections are closed after this duration. | -| WithMaxConnWaitTimeout | 0s | maximum duration for waiting for a free connection. | -| WithKeepAlive | true | determines whether use keep-alive connection, default use. | -| WithClientReadTimeout | 0s | maximum duration for full response reading (including body). | +| **Option** | **Default** | **Description** | +| --------------------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| WithDialTimeout | 1s | dial timeout. | +| WithMaxConnsPerHost | 512 | maximum number of connections per host which may be established. | +| WithMaxIdleConnDuration | 10s | max idle connection duration, idle keep-alive connections are closed after this duration. | +| WithMaxConnDuration | 0s | max connection duration, keep-alive connections are closed after this duration. | +| WithMaxConnWaitTimeout | 0s | maximum duration for waiting for a free connection. | +| WithKeepAlive | true | determines whether use keep-alive connection, default use. | +| WithClientReadTimeout | 0s | maximum duration for full response reading (including body). | | WithTLSConfig | nil | tlsConfig to create a tls connection, for specific configuration information, please refer to [tls](/docs/hertz/tutorials/basic-feature/protocol/tls/). | -| WithDialer | network.Dialer | specific dialer. | -| WithResponseBodyStream | false | determine whether read body in stream or not, default not read in stream. | -| WithDisableHeaderNamesNormalizing | false | whether disable header names normalizing, default not disabled, for example, cONTENT-lenGTH -> Content-Length. | -| WithName | "" | set client name which used in User-Agent Header. | -| WithNoDefaultUserAgentHeader | false | whether default no User-Agent header, default with User-Agent header. | -| WithDisablePathNormalizing | false | whether disable path normalizing, default specification path, for example, http://localhost:8080/hello/../ hello -> http://localhost:8080/hello. | -| WithRetryConfig | nil | retry configuration, for specific configuration information, please refer to [retry](/docs/hertz/tutorials/basic-feature/retry/). | -| WithWriteTimeout | 0s | write timeout. | -| WithConnStateObserve | nil, 5s | set function to observe and record the connection status of HTTP client, as well as observe execution intervals. | -| WithDialFunc | network.Dialer | set dialer function. | -| WithHostClientConfigHook | nil | Set the hook function for re-configure the host client. | +| WithDialer | network.Dialer | specific dialer. | +| WithResponseBodyStream | false | determine whether read body in stream or not, default not read in stream. | +| WithDisableHeaderNamesNormalizing | false | whether disable header names normalizing, default not disabled, for example, cONTENT-lenGTH -> Content-Length. | +| WithName | "" | set client name which used in User-Agent Header. | +| WithNoDefaultUserAgentHeader | false | whether default no User-Agent header, default with User-Agent header. | +| WithDisablePathNormalizing | false | whether disable path normalizing, default specification path, for example, http://localhost:8080/hello/../ hello -> http://localhost:8080/hello. | +| WithRetryConfig | nil | retry configuration, for specific configuration information, please refer to [retry](/docs/hertz/tutorials/basic-feature/retry/). | +| WithWriteTimeout | 0s | write timeout. | +| WithConnStateObserve | nil, 5s | set function to observe and record the connection status of HTTP client, as well as observe execution intervals. | +| WithDialFunc | network.Dialer | set dialer function. | +| WithHostClientConfigHook | nil | Set the hook function for re-configure the host client. | Sample Code: @@ -121,14 +127,14 @@ func main() { ## Client Request Config -| **Option** | **Default** | **Description** | -| ----------------------------- | -------------- | ------------------------------------------------------- | -| WithDialTimeout | 0s | Dial timeout time, **this configuration item has a higher priority than the client configuration, which will overwrite the corresponding client configuration item**. | -| WithReadTimeout | 0s | The maximum duration of a complete read response (including body), **this configuration item has a higher priority than the client configuration, which will overwrite the corresponding client configuration item**. | -| WithWriteTimeout | 0s | HTTP client write timeout, **this configuration item has a higher priority than the client configuration, which will overwrite the corresponding client configuration item**. | -| WithRequestTimeout | 0s | The timeout for a complete HTTP request. | -| WithTag | make(map[string]string) | Set the tags field in the form of key-value, used in conjunction with service discovery, details can be found in [WithTag](/docs/hertz/tutorials/service-governance/service_discovery/#withtag). | -| WithSD | false | Used in conjunction with service discovery, this request uses service discovery when true is passed, details can be found in [WithSD](/docs/hertz/tutorials/service-governance/service_discovery/#withsd). | +| **Option** | **Default** | **Description** | +| ------------------ | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| WithDialTimeout | 0s | Dial timeout time, **this configuration item has a higher priority than the client configuration, which will overwrite the corresponding client configuration item**. | +| WithReadTimeout | 0s | The maximum duration of a complete read response (including body), **this configuration item has a higher priority than the client configuration, which will overwrite the corresponding client configuration item**. | +| WithWriteTimeout | 0s | HTTP client write timeout, **this configuration item has a higher priority than the client configuration, which will overwrite the corresponding client configuration item**. | +| WithRequestTimeout | 0s | The timeout for a complete HTTP request. | +| WithTag | make(map[string]string) | Set the tags field in the form of key-value, used in conjunction with service discovery, details can be found in [WithTag](/docs/hertz/tutorials/service-governance/service_discovery/#withtag). | +| WithSD | false | Used in conjunction with service discovery, this request uses service discovery when true is passed, details can be found in [WithSD](/docs/hertz/tutorials/service-governance/service_discovery/#withsd). | Sample Code: @@ -172,7 +178,7 @@ If resp is nil, the response will be ignored. If all DefaultMaxConnsPerHost conn Function Signature: ```go -func (c *Client) Do(ctx context.Context, req *protocol.Request, resp *protocol.Response) error +func (c *Client) Do(ctx context.Context, req *protocol.Request, resp *protocol.Response) error ``` Sample Code: @@ -605,7 +611,7 @@ func main() { if err != nil { return } - + req, res := &protocol.Request{}, &protocol.Response{} req.SetMethod(consts.MethodGet) req.SetRequestURI("https://www.example.com") @@ -743,7 +749,7 @@ The `UseAsLast` function adds the middleware to the end of the client middleware If the client middleware chain has already set the last middleware before, the `UseAsLast` function will return an `errorLastMiddlewareExist` error. Therefore, to ensure that the last middleware in the client middleware chain is empty, you can first use the [TakeOutLastMiddleware](#takeoutlastmiddleware) function to clear the last middleware in the client middleware chain. ->Note: The `UseAsLast` function sets the middleware in `c.lastMiddleware`, while the middleware chain set using the [Use](#use) function is stored in `c.mws`. The two functions are relatively independent. `c.lastMiddleware` is executed only at the end of the client middleware chain. Therefore, the `UseAsLast` function can be called before or after the [Use](#use) function. +> Note: The `UseAsLast` function sets the middleware in `c.lastMiddleware`, while the middleware chain set using the [Use](#use) function is stored in `c.mws`. The two functions are relatively independent. `c.lastMiddleware` is executed only at the end of the client middleware chain. Therefore, the `UseAsLast` function can be called before or after the [Use](#use) function. Function Signature: diff --git a/content/en/docs/hertz/tutorials/basic-feature/constants.md b/content/en/docs/hertz/tutorials/basic-feature/constants.md index b6909e272a..80a7a4cbe6 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/constants.md +++ b/content/en/docs/hertz/tutorials/basic-feature/constants.md @@ -2,7 +2,15 @@ title: "Constants" date: 2023-05-24 weight: 17 -keywords: ["Constants", "HTTP method", "HTTP MIME type", "HTTP status code", "HTTP Header", "HTTP protocol version"] +keywords: + [ + "Constants", + "HTTP method", + "HTTP MIME type", + "HTTP status code", + "HTTP Header", + "HTTP protocol version", + ] description: "Constants defined in Hertz for user use." --- @@ -28,7 +36,7 @@ const ( ### HTTP MIME type ```go -const ( +const ( // MIME text MIMETextPlain = "text/plain" MIMETextPlainUTF8 = "text/plain; charset=utf-8" diff --git a/content/en/docs/hertz/tutorials/basic-feature/context/_index.md b/content/en/docs/hertz/tutorials/basic-feature/context/_index.md index 433a1f1349..ef285abfdc 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/context/_index.md +++ b/content/en/docs/hertz/tutorials/basic-feature/context/_index.md @@ -2,7 +2,14 @@ title: "RequestContext" date: 2023-07-11 weight: 5 -keywords: ["RequestContext", "HTTP", "Context Passing", "Metadata Storage", "concurrent security"] +keywords: + [ + "RequestContext", + "HTTP", + "Context Passing", + "Metadata Storage", + "concurrent security", + ] description: "Functions related to the request context." --- @@ -19,7 +26,7 @@ type HandlerFunc func(c context.Context, ctx *RequestContext) ### Metadata Storage Both contexts have the ability to store values, and there is a simple basis for choosing which context to use: the lifecycle of the stored value and the chosen context should match. - + `ctx` is mainly used to store request level variables, which are reclaimed upon completion of the request. It's characteristics are high query efficiency (with the underlying `map`), unsafe coroutines, and no implementation of the `context.Context` interface. `c` is passed as a context between middleware `/handler`. it is coroutine security. For all places that require the `context.Context` interface as input parameters, simply pass `c` directly. diff --git a/content/en/docs/hertz/tutorials/basic-feature/context/request.md b/content/en/docs/hertz/tutorials/basic-feature/context/request.md index 5396994834..3f0ef2369a 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/context/request.md +++ b/content/en/docs/hertz/tutorials/basic-feature/context/request.md @@ -2,24 +2,36 @@ title: "Request" date: 2023-07-11 weight: 1 -keywords: ["RequestContext", "URI", "Header", "Body", "File Operation", "Metadata Store", "Handler", "Request", "Binding and validate", "ClientIP", "Concurrent Security"] +keywords: + [ + "RequestContext", + "URI", + "Header", + "Body", + "File Operation", + "Metadata Store", + "Handler", + "Request", + "Binding and validate", + "ClientIP", + "Concurrent Security", + ] description: "The functions related to the request in RequestContext." --- - ## URI ```go -func (ctx *RequestContext) Host() []byte -func (ctx *RequestContext) FullPath() string +func (ctx *RequestContext) Host() []byte +func (ctx *RequestContext) FullPath() string func (ctx *RequestContext) SetFullPath(p string) -func (ctx *RequestContext) Path() []byte +func (ctx *RequestContext) Path() []byte func (ctx *RequestContext) Param(key string) string func (ctx *RequestContext) Query(key string) string func (ctx *RequestContext) DefaultQuery(key, defaultValue string) string -func (ctx *RequestContext) GetQuery(key string) (string, bool) +func (ctx *RequestContext) GetQuery(key string) (string, bool) func (ctx *RequestContext) QueryArgs() *protocol.Args -func (ctx *RequestContext) URI() *protocol.URI +func (ctx *RequestContext) URI() *protocol.URI ``` ### Host @@ -29,7 +41,7 @@ Obtain the requested host address. Function Signature: ```go -func (ctx *RequestContext) Host() []byte +func (ctx *RequestContext) Host() []byte ``` Example Code: @@ -48,7 +60,7 @@ Get the complete path of the matched route, and return an empty string for the u Function Signature: ```go -func (ctx *RequestContext) FullPath() string +func (ctx *RequestContext) FullPath() string ``` Example Code: @@ -102,7 +114,7 @@ Obtain the path of the request. Function Signature: ```go -func (ctx *RequestContext) Path() []byte +func (ctx *RequestContext) Path() []byte ``` Example Code: @@ -121,7 +133,7 @@ Obtain the value of routing parameters. Function Signature: ```go -func (ctx *RequestContext) Param(key string) string +func (ctx *RequestContext) Param(key string) string ``` Example Code: @@ -210,25 +222,25 @@ func (ctx *RequestContext) QueryArgs() *protocol.Args The Args object provides the following methods to obtain/set `Query String` parameters. -|Function Signature | Description | -|:--|:--| -|`func (a *Args) Set(key, value string)` |Set the value of Args object key | -|`func (a *Args) Reset()` |Reset Args Object | -|`func (a *Args) CopyTo(dst *Args)` |Copy Args object to dst | -|`func (a *Args) Del(key string)` |Delete the key value pair of Args object key | -|`func (a *Args) DelBytes(key []byte)`|Delete key value pairs of Args object byte array type key | -|`func (a *Args) Has(key string) bool` |Obtain whether the Args object has a key value pair for the key | -|`func (a *Args) String() string` |Convert Args object to Query String of string type | -|`func (a *Args) QueryString() []byte` |Convert Args object to a Query String of byte array type | -|`func (a *Args) ParseBytes(b []byte)` |Parsing byte arrays and storing key value pairs in Args object | -|`func (a *Args) Peek(key string) []byte` |Obtain the value of Args object key | -|`func (a *Args) PeekExists(key string) (string, bool)` |Obtain the value of Args object key and its existence | -|`func (a *Args) PeekAll(key string) [][]byte` | Obtain all values of Args object key | -|`func (a *Args) Len() int`|Obtain the number of Args object key-value pairs | -|`func (a *Args) AppendBytes(dst []byte) []byte` |Append Args object Query String to dst and return | -|`func (a *Args) VisitAll(f func(key, value []byte))` |Visit all key value pairs of Args object | -|`func (a *Args) WriteTo(w io.Writer) (int64, error)`|Write Args object Query String to io.Writer | -|`func (a *Args) Add(key, value string)` |Add Args object key as key value | +| Function Signature | Description | +| :----------------------------------------------------- | :-------------------------------------------------------------- | +| `func (a *Args) Set(key, value string)` | Set the value of Args object key | +| `func (a *Args) Reset()` | Reset Args Object | +| `func (a *Args) CopyTo(dst *Args)` | Copy Args object to dst | +| `func (a *Args) Del(key string)` | Delete the key value pair of Args object key | +| `func (a *Args) DelBytes(key []byte)` | Delete key value pairs of Args object byte array type key | +| `func (a *Args) Has(key string) bool` | Obtain whether the Args object has a key value pair for the key | +| `func (a *Args) String() string` | Convert Args object to Query String of string type | +| `func (a *Args) QueryString() []byte` | Convert Args object to a Query String of byte array type | +| `func (a *Args) ParseBytes(b []byte)` | Parsing byte arrays and storing key value pairs in Args object | +| `func (a *Args) Peek(key string) []byte` | Obtain the value of Args object key | +| `func (a *Args) PeekExists(key string) (string, bool)` | Obtain the value of Args object key and its existence | +| `func (a *Args) PeekAll(key string) [][]byte` | Obtain all values of Args object key | +| `func (a *Args) Len() int` | Obtain the number of Args object key-value pairs | +| `func (a *Args) AppendBytes(dst []byte) []byte` | Append Args object Query String to dst and return | +| `func (a *Args) VisitAll(f func(key, value []byte))` | Visit all key value pairs of Args object | +| `func (a *Args) WriteTo(w io.Writer) (int64, error)` | Write Args object Query String to io.Writer | +| `func (a *Args) Add(key, value string)` | Add Args object key as key value | Example Code: @@ -261,7 +273,7 @@ h.GET("/user", func(c context.Context, ctx *app.RequestContext) { // n == 31 err == nil s := req.BodyBuffer().String() // s == "name=bar&age=&pets=dog&pets=cat" - + // change args var newArgs protocol.Args args.CopyTo(&newArgs) @@ -295,48 +307,48 @@ Return the requested `URI` object. Function Signature: ```go -func (ctx *RequestContext) URI() *protocol.URI +func (ctx *RequestContext) URI() *protocol.URI ``` ### URI Object The URI object provides the following methods to obtain/set URI. -|Function Signature | Description | -|:--|:--| -| `func (u *URI) CopyTo(dst *URI)`|Copy a copy of the URI object to dst | -| `func (u *URI) QueryArgs() *Args`|Get [Args](#args) | -| `func (u *URI) Hash() []byte`|Obtain Hash value, such as Hash is **qwe** | -| `func (u *URI) SetHash(hash string)`|Set Hash | -| `func (u *URI) SetHashBytes(hash []byte)`|Set Hash of type `[]byte` | -| `func (u *URI) Username() []byte`|Get Username | -| `func (u *URI) SetUsername(username string)`|Set Username | -| `func (u *URI) SetUsernameBytes(username []byte)`|Set Username of type `[]byte` | -| `func (u *URI) Password() []byte`|Get Password | -| `func (u *URI) SetPassword(password string)`|Set Password | -| `func (u *URI) SetPasswordBytes(password []byte)`|Set Password of type `[]byte` | -| `func (u *URI) QueryString() []byte`|Get `Query String`, such as `Query String` is **baz=123**| -| `func (u *URI) SetQueryString(queryString string)`|Set `Query String`, note that after this method, use `RequestHeader.SetRequestURI` may overwrite the originally intended value| -| `func (u *URI) SetQueryStringBytes(queryString []byte)`|Set `Query String` of type `[]byte`, note that after this method, use `RequestHeader.SetRequestURI` may overwrite the originally intended value| -| `func (u *URI) Path() []byte`| Get Path, such as Path is **/user/he rtz** | -| `func (u *URI) PathOriginal() []byte`|Get Unescaped Path, such as Path is **/user/he%20rtz**| -| `func (u *URI) SetPath(path string)`|Set Path| -| `func (u *URI) SetPathBytes(path []byte)`|Set Path of type `[]byte`| -| `func (u *URI) String() string`|Obtain the complete URI, such as complete URI is | -| `func (u *URI) FullURI() []byte`|Obtain the complete URI of type `[]byte` | -| `func (u *URI) Scheme() []byte`|Obtain protocol, such as http | -| `func (u *URI) SetScheme(scheme string)`|Set protocol | -| `func (u *URI) SetSchemeBytes(scheme []byte)`|Set protocol of type `[]byte` | -| `func (u *URI) Host() []byte`|Set Host, such as Host is **example.com**| -| `func (u *URI) SetHost(host string)`|Set Host| -| `func (u *URI) SetHostBytes(host []byte)`|Set Host of type `[]byte` | -| `func (u *URI) LastPathSegment() []byte`|Obtain the last part of Path, for example, the last part of Path **/foo/bar/baz.html** is **baz.html**| -| `func (u *URI) Update(newURI string)`|Update URI| -| `func (u *URI) UpdateBytes(newURI []byte)`|Update URI of type `[]byte`| -| `func (u *URI) Parse(host, uri []byte)`|Initialize URI| -| `func (u *URI) AppendBytes(dst []byte) []byte`|Assign the complete URI to dst and return dst| -| `func (u *URI) RequestURI() []byte`|Get RequestURI, such as RequestURI is **/user?baz=123**| -| `func (u *URI) Reset()`|Reset URI| +| Function Signature | Description | +| :------------------------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------- | +| `func (u *URI) CopyTo(dst *URI)` | Copy a copy of the URI object to dst | +| `func (u *URI) QueryArgs() *Args` | Get [Args](#args) | +| `func (u *URI) Hash() []byte` | Obtain Hash value, such as Hash is **qwe** | +| `func (u *URI) SetHash(hash string)` | Set Hash | +| `func (u *URI) SetHashBytes(hash []byte)` | Set Hash of type `[]byte` | +| `func (u *URI) Username() []byte` | Get Username | +| `func (u *URI) SetUsername(username string)` | Set Username | +| `func (u *URI) SetUsernameBytes(username []byte)` | Set Username of type `[]byte` | +| `func (u *URI) Password() []byte` | Get Password | +| `func (u *URI) SetPassword(password string)` | Set Password | +| `func (u *URI) SetPasswordBytes(password []byte)` | Set Password of type `[]byte` | +| `func (u *URI) QueryString() []byte` | Get `Query String`, such as `Query String` is **baz=123** | +| `func (u *URI) SetQueryString(queryString string)` | Set `Query String`, note that after this method, use `RequestHeader.SetRequestURI` may overwrite the originally intended value | +| `func (u *URI) SetQueryStringBytes(queryString []byte)` | Set `Query String` of type `[]byte`, note that after this method, use `RequestHeader.SetRequestURI` may overwrite the originally intended value | +| `func (u *URI) Path() []byte` | Get Path, such as Path is **/user/he rtz** | +| `func (u *URI) PathOriginal() []byte` | Get Unescaped Path, such as Path is **/user/he%20rtz** | +| `func (u *URI) SetPath(path string)` | Set Path | +| `func (u *URI) SetPathBytes(path []byte)` | Set Path of type `[]byte` | +| `func (u *URI) String() string` | Obtain the complete URI, such as complete URI is | +| `func (u *URI) FullURI() []byte` | Obtain the complete URI of type `[]byte` | +| `func (u *URI) Scheme() []byte` | Obtain protocol, such as http | +| `func (u *URI) SetScheme(scheme string)` | Set protocol | +| `func (u *URI) SetSchemeBytes(scheme []byte)` | Set protocol of type `[]byte` | +| `func (u *URI) Host() []byte` | Set Host, such as Host is **example.com** | +| `func (u *URI) SetHost(host string)` | Set Host | +| `func (u *URI) SetHostBytes(host []byte)` | Set Host of type `[]byte` | +| `func (u *URI) LastPathSegment() []byte` | Obtain the last part of Path, for example, the last part of Path **/foo/bar/baz.html** is **baz.html** | +| `func (u *URI) Update(newURI string)` | Update URI | +| `func (u *URI) UpdateBytes(newURI []byte)` | Update URI of type `[]byte` | +| `func (u *URI) Parse(host, uri []byte)` | Initialize URI | +| `func (u *URI) AppendBytes(dst []byte) []byte` | Assign the complete URI to dst and return dst | +| `func (u *URI) RequestURI() []byte` | Get RequestURI, such as RequestURI is **/user?baz=123** | +| `func (u *URI) Reset()` | Reset URI | ## Header @@ -349,12 +361,12 @@ func (h *RequestHeader) String() string func (h *RequestHeader) VisitAll(f func(key, value []byte)) // RequestContext -func (ctx *RequestContext) IsGet() bool +func (ctx *RequestContext) IsGet() bool func (ctx *RequestContext) IsHead() bool func (ctx *RequestContext) IsPost() bool func (ctx *RequestContext) Method() []byte func (ctx *RequestContext) ContentType() []byte -func (ctx *RequestContext) IfModifiedSince(lastModified time.Time) bool +func (ctx *RequestContext) IfModifiedSince(lastModified time.Time) bool func (ctx *RequestContext) Cookie(key string) []byte func (ctx *RequestContext) UserAgent() []byte func (ctx *RequestContext) GetHeader(key string) []byte @@ -379,12 +391,12 @@ hertz.GET("/example", func(c context.Context, ctx *app.RequestContext) { ctx.Request.Header.Add("hertz1", "value1") ctx.Request.Header.Add("hertz1", "value2") ctx.Request.Header.SetContentTypeBytes([]byte("application/x-www-form-urlencoded")) - contentType1 := ctx.Request.Header.ContentType() + contentType1 := ctx.Request.Header.ContentType() // contentType1 == []byte("application/x-www-form-urlencoded") ctx.Request.Header.Add("Content-Type", "application/json; charset=utf-8") - hertz1 := ctx.Request.Header.GetAll("hertz1") + hertz1 := ctx.Request.Header.GetAll("hertz1") // hertz1 == []string{"value1", "value2"} - contentType2 := ctx.Request.Header.ContentType() + contentType2 := ctx.Request.Header.ContentType() // contentType2 == []byte("application/json; charset=utf-8") }) ``` @@ -408,12 +420,12 @@ hertz.GET("/example", func(c context.Context, ctx *app.RequestContext) { ctx.Request.Header.Set("hertz1", "value1") ctx.Request.Header.Set("hertz1", "value2") ctx.Request.Header.SetContentTypeBytes([]byte("application/x-www-form-urlencoded")) - contentType1 := ctx.Request.Header.ContentType() + contentType1 := ctx.Request.Header.ContentType() // contentType1 == []byte("application/x-www-form-urlencoded") ctx.Request.Header.Set("Content-Type", "application/json; charset=utf-8") - hertz1 := ctx.Request.Header.GetAll("hertz1") + hertz1 := ctx.Request.Header.GetAll("hertz1") // hertz1 == []string{"value2"} - contentType2 := ctx.Request.Header.ContentType() + contentType2 := ctx.Request.Header.ContentType() // contentType2 == []byte("application/json; charset=utf-8") }) ``` @@ -630,99 +642,99 @@ h.Post("/user", func(c context.Context, ctx *app.RequestContext) { Use `RequestContext.Request.Header` to obtain the RequestHeader object, which provides the following methods to obtain/set the request header. -|Function Signature | Description | -|:--|:--| -| `func (h *RequestHeader) Method() []byte`|Get Method | -| `func (h *RequestHeader) SetMethod(method string)`|Set Method| -| `func (h *RequestHeader) SetMethodBytes(method []byte)`|Set Method of type `[]byte` | -| `func (h *RequestHeader) IsGet() bool`|Determine if Method is GET| -| `func (h *RequestHeader) IsHead() bool`|Determine if Method is HEAD| -| `func (h *RequestHeader) IsPost() bool`|Determine if Method is POST| -| `func (h *RequestHeader) IsPut() bool`|Determine if Method is PUT| -| `func (h *RequestHeader) IsDelete() bool`|Determine if Method is DELETE| -| `func (h *RequestHeader) IsConnect() bool`|Determine if Method is CONNECT| -| `func (h *RequestHeader) IsOptions() bool`|Determine if Method is OPTIONS| -| `func (h *RequestHeader) IsTrace() bool`|Determine if Method is TRACE| -| `func (h *RequestHeader) IgnoreBody() bool`|Determine whether to ignore Body (Method GET/HEAD ignores Body)| -| `func (h *RequestHeader) RequestURI() []byte`|Get RequestURI| -| `func (h *RequestHeader) SetRequestURI(requestURI string)`|Set RequestURI| -| `func (h *RequestHeader) SetRequestURIBytes(requestURI []byte)`|Set RequestURI of type `[]byte` | -| `func (h *RequestHeader) SetProtocol(p string)`|Set protocol type, such as HTTP/1.0| -| `func (h *RequestHeader) GetProtocol() string`|Get protocol type, such as HTTP/1.1| -| `func (h *RequestHeader) IsHTTP11() bool`|Determine if it is HTTP/1.1| -| `func (h *RequestHeader) SetNoHTTP11(b bool)`|Setting is not HTTP/1.1| -| `func (h *RequestHeader) Host() []byte`|Get Host| -| `func (h *RequestHeader) SetHost(host string)`|Set Host| -| `func (h *RequestHeader) SetHostBytes(host []byte)`|Set Host of type `[]byte`| -| `func (h *RequestHeader) ContentLength() int`|Get Content-Length| -| `func (h *RequestHeader) ContentLengthBytes() []byte`|Get Content-Length of type `[]byte`| -| `func (h *RequestHeader) SetContentLength(contentLength int)`|Set Content-Length| -| `func (h *RequestHeader) SetContentLengthBytes(contentLength []byte)`|Set Content-Length of type `[]byte`| -| `func (h *RequestHeader) InitContentLengthWithValue(contentLength int)`|Initialize Content-Length| -| `func (h *RequestHeader) ContentType() []byte`|Get Content-Type| -| `func (h *RequestHeader) SetContentTypeBytes(contentType []byte)`|Set Content-Type| -| `func (h *RequestHeader) SetNoDefaultContentType(b bool)`|Control the default sending behavior when Content Type is not specified, false sends the default Content Type value, true does not send Content Type| -| `func (h *RequestHeader) UserAgent() []byte`|Get User-Agent| -| `func (h *RequestHeader) SetUserAgentBytes(userAgent []byte)`|Set User-Agent| -| `func (h *RequestHeader) ConnectionClose() bool`|Determine if it contains Connection: close| -| `func (h *RequestHeader) SetConnectionClose(close bool)`|Set connectionClose | -| `func (h *RequestHeader) ResetConnectionClose()`|Reset connectionClose to false and delete Connection Header| -| `func (h *RequestHeader) SetByteRange(startPos, endPos int)`|Set Range (Range: bytes=startPos-endPos)| -| `func (h *RequestHeader) SetMultipartFormBoundary(boundary string)`| Set the boundary for Content-Type=multipart/form data | -| `func (h *RequestHeader) MultipartFormBoundary() []byte`|Get the value of boundary | -| `func (h *RequestHeader) Trailer() *Trailer`|Get Trailer| -| `func (h *RequestHeader) Cookie(key string) []byte`|Obtain the value of Cookie key as key | -| `func (h *RequestHeader) SetCookie(key, value string)`|Set Cookie Key Values | -| `func (h *RequestHeader) DelCookie(key string)`|Delete the cookie whose key is key| -| `func (h *RequestHeader) DelAllCookies()`|Delete all Cookies | -| `func (h *RequestHeader) FullCookie() []byte`|Get all Cookies| -| `func (h *RequestHeader) Cookies() []*Cookie`|Get all Cookie objects | -| `func (h *RequestHeader) VisitAllCookie(f func(key, value []byte))`| Traverse the key values of all cookies and execute the f function | -| `func (h *RequestHeader) Peek(key string) []byte`|Obtain the value of key for type `[]byte` | -| `func (h *RequestHeader) Get(key string) string`|Obtain the value of key as key | -| `func (h *RequestHeader) PeekArgBytes(key []byte) []byte`|Obtain the value of key as key | -| `func (h *RequestHeader) PeekAll(key string) [][]byte`|Obtain all values of key for type `[]byte` (used to obtain multiple values with the same key)| -| `func (h *RequestHeader) GetAll(key string) []string`|Obtain all values with key as key | -| `func (h *RequestHeader) PeekIfModifiedSinceBytes() []byte`|Get If-Modified-Since| -| `func (h *RequestHeader) PeekContentEncoding() []byte`|Get Content-Encoding| -| `func (h *RequestHeader) PeekRange() []byte`|Get Range| -| `func (h *RequestHeader) HasAcceptEncodingBytes(acceptEncoding []byte) bool`|Determine whether Accept-Encoding exists and whether Accept-Encoding includes acceptEncoding| -| `func (h *RequestHeader) RawHeaders() []byte`|Get original Header | -| `func (h *RequestHeader) SetRawHeaders(r []byte)` | Set original Header | -| `func (h *RequestHeader) Add(key, value string)`| Set the header key value to set multiple headers for the same key, but the key will overwrite the following headers: Content-Type, Content-Length, Connection, Cookie, Transfer-Encoding, Host, User-Agent| -| `func (h *RequestHeader) InitBufValue(size int)`|Initialize buffer size | -| `func (h *RequestHeader) GetBufValue() []byte`|Get the value of the buffer | -| `func (h *RequestHeader) SetCanonical(key, value []byte)`|Set the Header key value, assuming that the key is in canonical form | -| `func (h *RequestHeader) Set(key, value string)`|Set the header key value to set a single header for the same key | -| `func (h *RequestHeader) SetBytesKV(key, value []byte)`|Set the header key value of type `[]byte` to set a single header for the same key | -| `func (h *RequestHeader) DelBytes(key []byte)`|Delete key value pairs with key in the header | -| `func (h *RequestHeader) AddArgBytes(key, value []byte, noValue bool)`|Add Header key value (different from `Add`, the key must not be normalized and will not undergo special processing when it is Content-Type, Content-Length, Connection, Cookie, Transfer-Encoding, Host, or User-Agent)| -| `func (h *RequestHeader) SetArgBytes(key, value []byte, noValue bool)`|Set Header key value (different from `Set`, The key must not be normalized and will not undergo special processing when it is Content-Type, Content-Length, Connection, Cookie, Transfer-Encoding, Host, or User-Agent)| -| `func (h *RequestHeader) AppendBytes(dst []byte) []byte`|Attach the complete header to the dst and return | -| `func (h *RequestHeader) Header() []byte`|Obtain the complete header of type `[]byte` | -| `func (h *RequestHeader) String() string`|Obtain the complete header | -| `func (h *RequestHeader) CopyTo(dst *RequestHeader)`|Obtain a copy of RequestHeader | -| `func (h *RequestHeader) VisitAll(f func(key, value []byte))`|Traverse the key values of all headers and execute the f function | -| `func (h *RequestHeader) VisitAllCustomHeader(f func(key, value []byte))`|Traverse the key values of all headers and execute the f function, except for Content-Type, Content-Length, Cookie, Host, User-Agent| -| `func (h *RequestHeader) Len() int`|Return the number of key value pairs in the header | -| `func (h *RequestHeader) DisableNormalizing()`|Disable the normalization of header name (capitalize the first letter and the first letter after the Em dash)| -| `func (h *RequestHeader) IsDisableNormalizing() bool`|Whether to disable standardized for header name, default not disabled | -| `func (h *RequestHeader) ResetSkipNormalize()`|Reset Headers except for disableNormalizing status | -| `func (h *RequestHeader) Reset()`|Reset Headers | +| Function Signature | Description | +| :--------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `func (h *RequestHeader) Method() []byte` | Get Method | +| `func (h *RequestHeader) SetMethod(method string)` | Set Method | +| `func (h *RequestHeader) SetMethodBytes(method []byte)` | Set Method of type `[]byte` | +| `func (h *RequestHeader) IsGet() bool` | Determine if Method is GET | +| `func (h *RequestHeader) IsHead() bool` | Determine if Method is HEAD | +| `func (h *RequestHeader) IsPost() bool` | Determine if Method is POST | +| `func (h *RequestHeader) IsPut() bool` | Determine if Method is PUT | +| `func (h *RequestHeader) IsDelete() bool` | Determine if Method is DELETE | +| `func (h *RequestHeader) IsConnect() bool` | Determine if Method is CONNECT | +| `func (h *RequestHeader) IsOptions() bool` | Determine if Method is OPTIONS | +| `func (h *RequestHeader) IsTrace() bool` | Determine if Method is TRACE | +| `func (h *RequestHeader) IgnoreBody() bool` | Determine whether to ignore Body (Method GET/HEAD ignores Body) | +| `func (h *RequestHeader) RequestURI() []byte` | Get RequestURI | +| `func (h *RequestHeader) SetRequestURI(requestURI string)` | Set RequestURI | +| `func (h *RequestHeader) SetRequestURIBytes(requestURI []byte)` | Set RequestURI of type `[]byte` | +| `func (h *RequestHeader) SetProtocol(p string)` | Set protocol type, such as HTTP/1.0 | +| `func (h *RequestHeader) GetProtocol() string` | Get protocol type, such as HTTP/1.1 | +| `func (h *RequestHeader) IsHTTP11() bool` | Determine if it is HTTP/1.1 | +| `func (h *RequestHeader) SetNoHTTP11(b bool)` | Setting is not HTTP/1.1 | +| `func (h *RequestHeader) Host() []byte` | Get Host | +| `func (h *RequestHeader) SetHost(host string)` | Set Host | +| `func (h *RequestHeader) SetHostBytes(host []byte)` | Set Host of type `[]byte` | +| `func (h *RequestHeader) ContentLength() int` | Get Content-Length | +| `func (h *RequestHeader) ContentLengthBytes() []byte` | Get Content-Length of type `[]byte` | +| `func (h *RequestHeader) SetContentLength(contentLength int)` | Set Content-Length | +| `func (h *RequestHeader) SetContentLengthBytes(contentLength []byte)` | Set Content-Length of type `[]byte` | +| `func (h *RequestHeader) InitContentLengthWithValue(contentLength int)` | Initialize Content-Length | +| `func (h *RequestHeader) ContentType() []byte` | Get Content-Type | +| `func (h *RequestHeader) SetContentTypeBytes(contentType []byte)` | Set Content-Type | +| `func (h *RequestHeader) SetNoDefaultContentType(b bool)` | Control the default sending behavior when Content Type is not specified, false sends the default Content Type value, true does not send Content Type | +| `func (h *RequestHeader) UserAgent() []byte` | Get User-Agent | +| `func (h *RequestHeader) SetUserAgentBytes(userAgent []byte)` | Set User-Agent | +| `func (h *RequestHeader) ConnectionClose() bool` | Determine if it contains Connection: close | +| `func (h *RequestHeader) SetConnectionClose(close bool)` | Set connectionClose | +| `func (h *RequestHeader) ResetConnectionClose()` | Reset connectionClose to false and delete Connection Header | +| `func (h *RequestHeader) SetByteRange(startPos, endPos int)` | Set Range (Range: bytes=startPos-endPos) | +| `func (h *RequestHeader) SetMultipartFormBoundary(boundary string)` | Set the boundary for Content-Type=multipart/form data | +| `func (h *RequestHeader) MultipartFormBoundary() []byte` | Get the value of boundary | +| `func (h *RequestHeader) Trailer() *Trailer` | Get Trailer | +| `func (h *RequestHeader) Cookie(key string) []byte` | Obtain the value of Cookie key as key | +| `func (h *RequestHeader) SetCookie(key, value string)` | Set Cookie Key Values | +| `func (h *RequestHeader) DelCookie(key string)` | Delete the cookie whose key is key | +| `func (h *RequestHeader) DelAllCookies()` | Delete all Cookies | +| `func (h *RequestHeader) FullCookie() []byte` | Get all Cookies | +| `func (h *RequestHeader) Cookies() []*Cookie` | Get all Cookie objects | +| `func (h *RequestHeader) VisitAllCookie(f func(key, value []byte))` | Traverse the key values of all cookies and execute the f function | +| `func (h *RequestHeader) Peek(key string) []byte` | Obtain the value of key for type `[]byte` | +| `func (h *RequestHeader) Get(key string) string` | Obtain the value of key as key | +| `func (h *RequestHeader) PeekArgBytes(key []byte) []byte` | Obtain the value of key as key | +| `func (h *RequestHeader) PeekAll(key string) [][]byte` | Obtain all values of key for type `[]byte` (used to obtain multiple values with the same key) | +| `func (h *RequestHeader) GetAll(key string) []string` | Obtain all values with key as key | +| `func (h *RequestHeader) PeekIfModifiedSinceBytes() []byte` | Get If-Modified-Since | +| `func (h *RequestHeader) PeekContentEncoding() []byte` | Get Content-Encoding | +| `func (h *RequestHeader) PeekRange() []byte` | Get Range | +| `func (h *RequestHeader) HasAcceptEncodingBytes(acceptEncoding []byte) bool` | Determine whether Accept-Encoding exists and whether Accept-Encoding includes acceptEncoding | +| `func (h *RequestHeader) RawHeaders() []byte` | Get original Header | +| `func (h *RequestHeader) SetRawHeaders(r []byte)` | Set original Header | +| `func (h *RequestHeader) Add(key, value string)` | Set the header key value to set multiple headers for the same key, but the key will overwrite the following headers: Content-Type, Content-Length, Connection, Cookie, Transfer-Encoding, Host, User-Agent | +| `func (h *RequestHeader) InitBufValue(size int)` | Initialize buffer size | +| `func (h *RequestHeader) GetBufValue() []byte` | Get the value of the buffer | +| `func (h *RequestHeader) SetCanonical(key, value []byte)` | Set the Header key value, assuming that the key is in canonical form | +| `func (h *RequestHeader) Set(key, value string)` | Set the header key value to set a single header for the same key | +| `func (h *RequestHeader) SetBytesKV(key, value []byte)` | Set the header key value of type `[]byte` to set a single header for the same key | +| `func (h *RequestHeader) DelBytes(key []byte)` | Delete key value pairs with key in the header | +| `func (h *RequestHeader) AddArgBytes(key, value []byte, noValue bool)` | Add Header key value (different from `Add`, the key must not be normalized and will not undergo special processing when it is Content-Type, Content-Length, Connection, Cookie, Transfer-Encoding, Host, or User-Agent) | +| `func (h *RequestHeader) SetArgBytes(key, value []byte, noValue bool)` | Set Header key value (different from `Set`, The key must not be normalized and will not undergo special processing when it is Content-Type, Content-Length, Connection, Cookie, Transfer-Encoding, Host, or User-Agent) | +| `func (h *RequestHeader) AppendBytes(dst []byte) []byte` | Attach the complete header to the dst and return | +| `func (h *RequestHeader) Header() []byte` | Obtain the complete header of type `[]byte` | +| `func (h *RequestHeader) String() string` | Obtain the complete header | +| `func (h *RequestHeader) CopyTo(dst *RequestHeader)` | Obtain a copy of RequestHeader | +| `func (h *RequestHeader) VisitAll(f func(key, value []byte))` | Traverse the key values of all headers and execute the f function | +| `func (h *RequestHeader) VisitAllCustomHeader(f func(key, value []byte))` | Traverse the key values of all headers and execute the f function, except for Content-Type, Content-Length, Cookie, Host, User-Agent | +| `func (h *RequestHeader) Len() int` | Return the number of key value pairs in the header | +| `func (h *RequestHeader) DisableNormalizing()` | Disable the normalization of header name (capitalize the first letter and the first letter after the Em dash) | +| `func (h *RequestHeader) IsDisableNormalizing() bool` | Whether to disable standardized for header name, default not disabled | +| `func (h *RequestHeader) ResetSkipNormalize()` | Reset Headers except for disableNormalizing status | +| `func (h *RequestHeader) Reset()` | Reset Headers | ## Body ```go func (ctx *RequestContext) GetRawData() []byte -func (ctx *RequestContext) Body() ([]byte, error) +func (ctx *RequestContext) Body() ([]byte, error) func (ctx *RequestContext) RequestBodyStream() io.Reader func (ctx *RequestContext) MultipartForm() (*multipart.Form, error) func (ctx *RequestContext) PostForm(key string) string -func (ctx *RequestContext) DefaultPostForm(key, defaultValue string) string -func (ctx *RequestContext) GetPostForm(key string) (string, bool) +func (ctx *RequestContext) DefaultPostForm(key, defaultValue string) string +func (ctx *RequestContext) GetPostForm(key string) (string, bool) func (ctx *RequestContext) PostArgs() *protocol.Args -func (ctx *RequestContext) FormValue(key string) []byte -func (ctx *RequestContext) SetFormValueFunc(f FormValueFunc) +func (ctx *RequestContext) FormValue(key string) []byte +func (ctx *RequestContext) SetFormValueFunc(f FormValueFunc) ``` ### Body @@ -732,7 +744,7 @@ Obtain the requested body data and return an error if an error occurs. Function Signature: ```go -func (ctx *RequestContext) Body() ([]byte, error) +func (ctx *RequestContext) Body() ([]byte, error) ``` Example Code: @@ -785,7 +797,7 @@ Example Code: ```go // POST http://example.com/user -// Content-Type: multipart/form-data; +// Content-Type: multipart/form-data; // Content-Disposition: form-data; name="name" // tom h.POST("/user", func(c context.Context, ctx *app.RequestContext) { @@ -810,7 +822,7 @@ Example Code: ```go // POST http://example.com/user -// Content-Type: multipart/form-data; +// Content-Type: multipart/form-data; // Content-Disposition: form-data; name="name" // tom h.POST("/user", func(c context.Context, ctx *app.RequestContext) { @@ -827,14 +839,14 @@ Retrieve `multipart.Form.Value` by name and return the first value of the given Function Signature: ```go -func (ctx *RequestContext) DefaultPostForm(key, defaultValue string) string +func (ctx *RequestContext) DefaultPostForm(key, defaultValue string) string ``` Example Code: ```go // POST http://example.com/user -// Content-Type: multipart/form-data; +// Content-Type: multipart/form-data; // Content-Disposition: form-data; name="name" // tom h.POST("/user", func(c context.Context, ctx *app.RequestContext) { @@ -884,7 +896,7 @@ Obtain the values of keys in the following order. Function Signature: ```go -func (ctx *RequestContext) FormValue(key string) []byte +func (ctx *RequestContext) FormValue(key string) []byte ``` Example Code: @@ -899,7 +911,7 @@ h.POST("/user", func(c context.Context, ctx *app.RequestContext) { }) // POST http://example.com/user -// Content-Type: multipart/form-data; +// Content-Type: multipart/form-data; // Content-Disposition: form-data; name="name" // tom h.POST("/user", func(c context.Context, ctx *app.RequestContext) { @@ -914,14 +926,14 @@ If the default method provided by the [FormValue](#formvalue) function to obtain Function Signature: ```go -func (ctx *RequestContext) SetFormValueFunc(f FormValueFunc) +func (ctx *RequestContext) SetFormValueFunc(f FormValueFunc) ``` Example Code: ```go // POST http://example.com/user?name=tom -// Content-Type: multipart/form-data; +// Content-Type: multipart/form-data; // Content-Disposition: form-data; name="age" // 10 h.POST("/user", func(c context.Context, ctx *app.RequestContext) { @@ -946,8 +958,8 @@ h.POST("/user", func(c context.Context, ctx *app.RequestContext) { ```go func (ctx *RequestContext) MultipartForm() (*multipart.Form, error) -func (ctx *RequestContext) FormFile(name string) (*multipart.FileHeader, error) -func (ctx *RequestContext) SaveUploadedFile(file *multipart.FileHeader, dst string) error +func (ctx *RequestContext) FormFile(name string) (*multipart.FileHeader, error) +func (ctx *RequestContext) SaveUploadedFile(file *multipart.FileHeader, dst string) error ``` ### MultipartForm @@ -966,7 +978,7 @@ Example Code: ```go // POST http://example.com/user -// Content-Type: multipart/form-data; +// Content-Type: multipart/form-data; // Content-Disposition: form-data; name="avatar"; filename="abc.jpg" h.POST("/user", func(c context.Context, ctx *app.RequestContext) { form, err := ctx.MultipartForm() @@ -981,14 +993,14 @@ Retrieve `multipart.Form.File` by name and return the first `multipart.FileHeade Function Signature: ```go -func (ctx *RequestContext) FormFile(name string) (*multipart.FileHeader, error) +func (ctx *RequestContext) FormFile(name string) (*multipart.FileHeader, error) ``` Example Code: ```go // POST http://example.com/user -// Content-Type: multipart/form-data; +// Content-Type: multipart/form-data; // Content-Disposition: form-data; name="avatar"; filename="abc.jpg" h.Post("/user", func(c context.Context, ctx *app.RequestContext) { avatarFile, err := ctx.FormFile("avatar") // avatarFile.Filename == "abc.jpg", err == nil @@ -1002,14 +1014,14 @@ Save the multipart file to disk. Function Signature: ```go -func (ctx *RequestContext) SaveUploadedFile(file *multipart.FileHeader, dst string) error +func (ctx *RequestContext) SaveUploadedFile(file *multipart.FileHeader, dst string) error ``` Example Code: ```go // POST http://example.com/user -// Content-Type: multipart/form-data; +// Content-Type: multipart/form-data; // Content-Disposition: form-data; name="avatar"; filename="abc.jpg" h.Post("/user", func(c context.Context, ctx *app.RequestContext) { avatarFile, err := ctx.FormFile("avatar") // avatarFile.Filename == "abc.jpg", err == nil @@ -1022,29 +1034,29 @@ h.Post("/user", func(c context.Context, ctx *app.RequestContext) { > Note: RequestContext will be reclaimed after the request ends, and the metadata will be set to nil. To use asynchronously, please use the [Copy](#copy) method. -|Function Signature | Description | -|:--|:--| -| `func (ctx *RequestContext) Set(key string, value interface{})`|Store key value pairs in requestContext | -| `func (ctx *RequestContext) Value(key interface{}) interface{}`|Gets the value of the requestContext key as key | -| `func (ctx *RequestContext) Get(key string) (value interface{}, exists bool)`|Obtain the value of the requestContext key as key and whether the key exists | -| `func (ctx *RequestContext) MustGet(key string) interface{}`|Obtain the value of the requestContext key as key. If it does not exist, a panic will occur| -| `func (ctx *RequestContext) GetString(key string) (s string)`|Obtain the value of the requestContext key as key and convert it to type `string` | -| `func (ctx *RequestContext) GetBool(key string) (b bool)`|Obtain the value of the requestContext key as key and convert it to type `bool` | -| `func (ctx *RequestContext) GetInt(key string) (i int)`|Obtain the value of the requestContext key as key and convert it to type `int` | -| `func (ctx *RequestContext) GetInt32(key string) (i32 int32)`|Obtain the value of the requestContext key as key and convert it to type `int32` | -| `func (ctx *RequestContext) GetInt64(key string) (i64 int64)`|Obtain the value of the requestContext key as key and convert it to type `int64` | -| `func (ctx *RequestContext) GetUint(key string) (ui uint)`|Obtain the value of the requestContext key as key and convert it to type `uint` | -| `func (ctx *RequestContext) GetUint32(key string) (ui32 uint32)`|Obtain the value of the requestContext key as key and convert it to type `uint32` | -| `func (ctx *RequestContext) GetUint64(key string) (ui64 uint64)`|Obtain the value of the requestContext key as key and convert it to type `uint64` | -| `func (ctx *RequestContext) GetFloat32(key string) (f32 float32)`|Obtain the value of the requestContext key as key and convert it to type `float32` | -| `func (ctx *RequestContext) GetFloat64(key string) (f64 float64)`|Obtain the value of the requestContext key as key and convert it to type `float64` | -| `func (ctx *RequestContext) GetTime(key string) (t time.Time)`|Obtain the value of the requestContext key as key and convert it to type `time.Time` | -| `func (ctx *RequestContext) GetDuration(key string) (d time.Duration)`|Obtain the value of the requestContext key as key and convert it to type `time.Duration` | -| `func (ctx *RequestContext) GetStringSlice(key string) (ss []string)`|Obtain the value of the requestContext key as key and convert it to type `[]string` | -| `func (ctx *RequestContext) GetStringMap(key string) (sm map[string]interface{})`|Obtain the value of the requestContext key as key and convert it to type `map[string]interface{}` | -| `func (ctx *RequestContext) GetStringMapString(key string) (sms map[string]string)`|Obtain the value of the requestContext key as key and convert it to type `map[string]string` | -| `func (ctx *RequestContext) GetStringMapStringSlice(key string) (smss map[string][]string)`|Obtain the value of the requestContext key as key and convert it to type `map[string][]string` | -| `func (ctx *RequestContext) ForEachKey(fn func(k string, v interface{}))`|Call fn for each key value pair in the context | +| Function Signature | Description | +| :------------------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------ | +| `func (ctx *RequestContext) Set(key string, value interface{})` | Store key value pairs in requestContext | +| `func (ctx *RequestContext) Value(key interface{}) interface{}` | Gets the value of the requestContext key as key | +| `func (ctx *RequestContext) Get(key string) (value interface{}, exists bool)` | Obtain the value of the requestContext key as key and whether the key exists | +| `func (ctx *RequestContext) MustGet(key string) interface{}` | Obtain the value of the requestContext key as key. If it does not exist, a panic will occur | +| `func (ctx *RequestContext) GetString(key string) (s string)` | Obtain the value of the requestContext key as key and convert it to type `string` | +| `func (ctx *RequestContext) GetBool(key string) (b bool)` | Obtain the value of the requestContext key as key and convert it to type `bool` | +| `func (ctx *RequestContext) GetInt(key string) (i int)` | Obtain the value of the requestContext key as key and convert it to type `int` | +| `func (ctx *RequestContext) GetInt32(key string) (i32 int32)` | Obtain the value of the requestContext key as key and convert it to type `int32` | +| `func (ctx *RequestContext) GetInt64(key string) (i64 int64)` | Obtain the value of the requestContext key as key and convert it to type `int64` | +| `func (ctx *RequestContext) GetUint(key string) (ui uint)` | Obtain the value of the requestContext key as key and convert it to type `uint` | +| `func (ctx *RequestContext) GetUint32(key string) (ui32 uint32)` | Obtain the value of the requestContext key as key and convert it to type `uint32` | +| `func (ctx *RequestContext) GetUint64(key string) (ui64 uint64)` | Obtain the value of the requestContext key as key and convert it to type `uint64` | +| `func (ctx *RequestContext) GetFloat32(key string) (f32 float32)` | Obtain the value of the requestContext key as key and convert it to type `float32` | +| `func (ctx *RequestContext) GetFloat64(key string) (f64 float64)` | Obtain the value of the requestContext key as key and convert it to type `float64` | +| `func (ctx *RequestContext) GetTime(key string) (t time.Time)` | Obtain the value of the requestContext key as key and convert it to type `time.Time` | +| `func (ctx *RequestContext) GetDuration(key string) (d time.Duration)` | Obtain the value of the requestContext key as key and convert it to type `time.Duration` | +| `func (ctx *RequestContext) GetStringSlice(key string) (ss []string)` | Obtain the value of the requestContext key as key and convert it to type `[]string` | +| `func (ctx *RequestContext) GetStringMap(key string) (sm map[string]interface{})` | Obtain the value of the requestContext key as key and convert it to type `map[string]interface{}` | +| `func (ctx *RequestContext) GetStringMapString(key string) (sms map[string]string)` | Obtain the value of the requestContext key as key and convert it to type `map[string]string` | +| `func (ctx *RequestContext) GetStringMapStringSlice(key string) (smss map[string][]string)` | Obtain the value of the requestContext key as key and convert it to type `map[string][]string` | +| `func (ctx *RequestContext) ForEachKey(fn func(k string, v interface{}))` | Call fn for each key value pair in the context | Example Code: @@ -1123,13 +1135,13 @@ h.POST("/user", func(c context.Context, ctx *app.RequestContext) { ## Handler ```go -func (ctx *RequestContext) Next(c context.Context) -func (ctx *RequestContext) Handlers() HandlersChain -func (ctx *RequestContext) Handler() HandlerFunc -func (ctx *RequestContext) SetHandlers(hc HandlersChain) -func (ctx *RequestContext) HandlerName() string -func (ctx *RequestContext) GetIndex() int8 -func (ctx *RequestContext) Abort() +func (ctx *RequestContext) Next(c context.Context) +func (ctx *RequestContext) Handlers() HandlersChain +func (ctx *RequestContext) Handler() HandlerFunc +func (ctx *RequestContext) SetHandlers(hc HandlersChain) +func (ctx *RequestContext) HandlerName() string +func (ctx *RequestContext) GetIndex() int8 +func (ctx *RequestContext) Abort() func (ctx *RequestContext) IsAborted() bool ``` @@ -1317,16 +1329,16 @@ h.POST("/user", func(c context.Context, ctx *app.RequestContext) { (For more information, please refer to [binding-and-validate](/docs/hertz/tutorials/basic-feature/binding-and-validate)) ```go -func (ctx *RequestContext) Bind(obj interface{}) error -func (ctx *RequestContext) Validate(obj interface{}) error +func (ctx *RequestContext) Bind(obj interface{}) error +func (ctx *RequestContext) Validate(obj interface{}) error func (ctx *RequestContext) BindAndValidate(obj interface{}) error ``` ## Get ClientIP ```go -func (ctx *RequestContext) ClientIP() string -func (ctx *RequestContext) SetClientIPFunc(f ClientIP) +func (ctx *RequestContext) ClientIP() string +func (ctx *RequestContext) SetClientIPFunc(f ClientIP) ``` ### ClientIP @@ -1338,7 +1350,7 @@ The default behavior of this function: If there is an ip in the `X-Forwarded-For Function Signature: ```go -func (ctx *RequestContext) ClientIP() string +func (ctx *RequestContext) ClientIP() string ``` Example Code: @@ -1362,7 +1374,7 @@ Users can implement custom functions themselves or by setting `app.ClientIPOptio Function Signature: ```go -func (ctx *RequestContext) SetClientIPFunc(f ClientIP) +func (ctx *RequestContext) SetClientIPFunc(f ClientIP) ``` Example Code: @@ -1403,7 +1415,7 @@ Copy a copy of RequestContext to provide secure access to the coroutine. Function Signature: ```go -func (ctx *RequestContext) Copy() *RequestContext +func (ctx *RequestContext) Copy() *RequestContext ``` Example Code: diff --git a/content/en/docs/hertz/tutorials/basic-feature/context/response.md b/content/en/docs/hertz/tutorials/basic-feature/context/response.md index 32d7f22563..1a507d0057 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/context/response.md +++ b/content/en/docs/hertz/tutorials/basic-feature/context/response.md @@ -2,7 +2,16 @@ title: "Response" date: 2023-07-10 weight: 2 -keywords: ["RequestContext", "Render", "Header", "Body", "File operation", "Response", "Flush"] +keywords: + [ + "RequestContext", + "Render", + "Header", + "Body", + "File operation", + "Response", + "Flush", + ] description: "The functions related to the response in RequestContext." --- @@ -20,7 +29,7 @@ func (ctx *RequestContext) Redirect(statusCode int, uri []byte) func (ctx *RequestContext) Header(key, value string) func (ctx *RequestContext) SetCookie(name, value string, maxAge int, path, domain string, sameSite protocol.CookieSameSite, secure, httpOnly bool) func (ctx *RequestContext) AbortWithStatus(code int) -func (ctx *RequestContext) AbortWithError(code int, err error) *errors.Error +func (ctx *RequestContext) AbortWithError(code int, err error) *errors.Error ``` ### SetContentType @@ -226,7 +235,7 @@ Example Code: ```go h.GET("/user", func(c context.Context, ctx *app.RequestContext) { ctx.SetCookie("user", "hertz", 1, "/", "localhost", protocol.CookieSameSiteLaxMode, true, true) - cookie := ctx.Response.Header.Get("Set-Cookie") + cookie := ctx.Response.Header.Get("Set-Cookie") // cookie == "user=hertz; max-age=1; domain=localhost; path=/; HttpOnly; secure; SameSite=Lax" }) ``` @@ -250,7 +259,7 @@ func SetPartitionedCookie(ctx *app.RequestContext, name, value string, maxAge in } cookie := protocol.AcquireCookie() defer protocol.ReleaseCookie(cookie) - // It is recommended to use the __Host prefix when setting partitioned cookies + // It is recommended to use the __Host prefix when setting partitioned cookies // to make them bound to the hostname (and not the registrable domain). cookie.SetKey(name) cookie.SetValue(url.QueryEscape(value)) @@ -306,7 +315,7 @@ Set the Status Code and collect Errors, terminate subsequent handlers, and retur Function Signature: ```go -func (ctx *RequestContext) AbortWithError(code int, err error) *errors.Error +func (ctx *RequestContext) AbortWithError(code int, err error) *errors.Error ``` Example Code: @@ -325,66 +334,66 @@ h.GET("/user", func(c context.Context, ctx *app.RequestContext) { Use RequestContext.Response.Header to obtain the ResponseHeader object, this object provides the following methods to obtain/set the response header. -|Function Signature | Description | -|:--|:--| -|`func (h *ResponseHeader) IsHTTP11() bool` |Determine if it is the `HTTP/1.1` protocol, and true indicates it is the `HTTP/1.1` protocol | -|`func (h *ResponseHeader) SetHeaderLength(length int)` |Set the length of the response header | -|`func (h *ResponseHeader) GetHeaderLength()` |Get the length of the response header | -|`func (h *ResponseHeader) SetContentRange(startPos, endPos, contentLength int)` |Set `Content-Range: bytes startPos-endPos/contentLength` in the response header, such as `Content-Range: bytes 1-5/10` | -|`func (h *ResponseHeader) NoDefaultContentType() bool` |Obtain the default sending behavior when no Content-Type is specified. False indicates sending the default Content-Type value, true indicates not sending, and the default Content-Type value is `text/plain; charset=utf-8` | -|`func (h *ResponseHeader) SetNoDefaultContentType(b bool)` |Set the default sending behavior when no Content-Type is specified. False indicates sending the default Content-Type value, true indicates not sending, and the default Content-Type value is `text/plain; charset=utf-8` | -|`func (h *ResponseHeader) SetContentType(contentType string)` |Set Content-Type | -|`func (h *ResponseHeader) ContentType() []byte` |Obtain Content-Type | -|`func (h *ResponseHeader) SetContentTypeBytes(contentType []byte)` |Set Content-Type | -|`func (h *ResponseHeader) ContentLength() int` |Obtain Content-Length, which can be a negative value. -1 represents `Transfer-Encoding: chunked`, -2 represents `Transfer-Encoding: identity` | -|`func (h *ResponseHeader) SetContentLength(contentLength int)` |Set Content-Length, which can be a negative value. -1 represents `Transfer-Encoding: chunked`, -2 represents `Transfer-Encoding: identity` | -|`func (h *ResponseHeader) SetContentLengthBytes(contentLength []byte)` |Set Content-Length for type `[]byte`, which can be a negative value. -1 represents `Transfer-Encoding: chunked`, -2 represents `Transfer-Encoding: identity` | -|`func (h *ResponseHeader) CopyTo(dst *ResponseHeader)` |Return a copy of the response header, which can be used when there is competitive access to the response header | -|`func (h *ResponseHeader) GetHeaders() []argsKV` |Return all response headers in the form of key value pairs | -|`func (h *ResponseHeader) VisitAll(f func(key, value []byte))` |Visit all the key values of all headers and execute the f function | -|`func (h *ResponseHeader) Get(key string) string` |Obtain the value of key, concurrency security | -|`func (h *ResponseHeader) GetAll(key string) []string` |Obtain all values of key with type `[]byte` (used to obtain multiple values with the same key), concurrency safety | -|`func (h *ResponseHeader) Peek(key string) []byte` |Obtain a key value of type `[]byte` as key, which is not secure for concurrency, and using `Get` when competing for access | -|`func (h *ResponseHeader) PeekAll(key string) [][]byte` |Obtain all values of type `[]byte` key as key (used to obtain multiple values with the same key), which is not secure for concurrency, and uses `GetAll` when competing for access | -|`func (h *ResponseHeader) Set(key, value string)` |Set the header key value to set a single header for the same key | -|`func (h *ResponseHeader) SetBytesV(key string, value []byte)` |Set the header key value of type `[]byte` to set a single header for the same key | -|`func (h *ResponseHeader) Add(key, value string)` |Set the header key value to set multiple headers for the same key, but the key will overwrite the following headers: Content Type, Content Length, Connection, Cookie, Transfer Encoding, Host, User Agent | -| `func (h *ResponseHeader) AddArgBytes(key, value []byte, noValue bool)`|Add Header key value (different from `Add`, the key must not be normalized and will not undergo special processing when it is Content-Type, Content-Length, Content-Encoding, Connection, Server, Set-Cookie, Transfer-Encoding)| -| `func (h *ResponseHeader) SetArgBytes(key, value []byte, noValue bool)`|Set Header key value (different from `Set`, the key must not be normalized and will not undergo special processing when it is Content-Type, Content-Length, Content-Encoding, Connection, Server, Set-Cookie, Transfer-Encoding)| -|`func (h *ResponseHeader) Del(key string)` |Delete key value pairs with key in the header | -|`func (h *ResponseHeader) DelBytes(key []byte)` |Delete key value pairs with key in the header | -|`func (h *ResponseHeader) AppendBytes(dst []byte) []byte` |Attach the complete header to the dst and return | -|`func (h *ResponseHeader) Header() []byte` |Obtain the complete header of type `[]byte` | -|`func (h *ResponseHeader) PeekLocation() []byte` |Return the value with key `Location` in the header | -|`func (h *ResponseHeader) Cookie(cookie *Cookie) bool` |Fill cookie for the given cookie.Key, and return false if the cookie.Key is missing | -|`func (h *RequestHeader) FullCookie() []byte` |Return the complete cookie as a byte array | -|`func (h *ResponseHeader) SetCookie(cookie *Cookie)` |Set Cookie Key Values | -|`func (h *ResponseHeader) VisitAllCookie(f func(key, value []byte))` |Visit all the key values of all cookies and execute the f function | -|`func (h *ResponseHeader) DelAllCookies()` |Delete all cookies | -|`func (h *ResponseHeader) DelCookie(key string)` |Delete cookie with key in the response header. To delete cookies from the client, use the `DelClientCookie` function | -|`func (h *ResponseHeader) DelCookieBytes(key []byte)` |Delete cookie with key in the response header. To delete cookies from the client, use the `DelClientCookieBytes` function | -|`func (h *ResponseHeader) DelClientCookie(key string)` |Remove the cookie from the client | -|`func (h *ResponseHeader) DelClientCookieBytes(key []byte)` |Remove the cookie from the client | -|`func (h *ResponseHeader) SetConnectionClose(close bool)`|Set the `Connection: close` flag in the response header | -|`func (h *ResponseHeader) ConnectionClose() bool` |Determine if Connection: close is included | -|`func (h *ResponseHeader) ContentEncoding() []byte` |Obtion Content-Encoding | -|`func (h *ResponseHeader) SetContentEncoding(contentEncoding string)` |Set Content-Encoding | -|`func (h *ResponseHeader) SetContentEncodingBytes(contentEncoding []byte)` |Set Content-Encoding | -|`func (h *ResponseHeader) SetCanonical(key, value []byte)` |Set the Header key value, assuming that the key is in canonical form | -|`func (h *ResponseHeader) Server() []byte` |Return the value with key `Server` in the header | -|`func (h *ResponseHeader) SetServerBytes(server []byte)` |Set the key in the header to the value of Server | -|`func (h *ResponseHeader) MustSkipContentLength() bool` |Determine if there is a response body (according to the HTTP/1.1 protocol, there is no response body when the response status codes are 1xx, 204, or 304) | -|`func (h *ResponseHeader) StatusCode() int` |Obtion StatusCode | -|`func (h *ResponseHeader) SetStatusCode(statusCode int)`|Set StatusCode | -|`func (h *ResponseHeader) Len() int` |Return the number of headers | -|`func (h *ResponseHeader) DisableNormalizing()` |Disable the normalization of header name (capitalize the first letter and the first letter after the Em dash) | -|`func (h *ResponseHeader) IsDisableNormalizing() bool` |Whether to disable the normalization of header names, default not disabled | -|`func (h *ResponseHeader) Trailer() *Trailer` |Get Trailer | -|`func (h *ResponseHeader) SetProtocol(p string)` |Set protocol name | -|`func (h *ResponseHeader) GetProtocol() string` |Get protocol name | -|`func (h *ResponseHeader) Reset()`|Reset the response header | -|`func (h *ResponseHeader) ResetSkipNormalize()` |Reset the response header, except for the `disableNormalizing` state | -|`func (h *ResponseHeader) ResetConnectionClose()` |Reset the connectionClose flag to false and delete the Connection Header | +| Function Signature | Description | +| :------------------------------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `func (h *ResponseHeader) IsHTTP11() bool` | Determine if it is the `HTTP/1.1` protocol, and true indicates it is the `HTTP/1.1` protocol | +| `func (h *ResponseHeader) SetHeaderLength(length int)` | Set the length of the response header | +| `func (h *ResponseHeader) GetHeaderLength()` | Get the length of the response header | +| `func (h *ResponseHeader) SetContentRange(startPos, endPos, contentLength int)` | Set `Content-Range: bytes startPos-endPos/contentLength` in the response header, such as `Content-Range: bytes 1-5/10` | +| `func (h *ResponseHeader) NoDefaultContentType() bool` | Obtain the default sending behavior when no Content-Type is specified. False indicates sending the default Content-Type value, true indicates not sending, and the default Content-Type value is `text/plain; charset=utf-8` | +| `func (h *ResponseHeader) SetNoDefaultContentType(b bool)` | Set the default sending behavior when no Content-Type is specified. False indicates sending the default Content-Type value, true indicates not sending, and the default Content-Type value is `text/plain; charset=utf-8` | +| `func (h *ResponseHeader) SetContentType(contentType string)` | Set Content-Type | +| `func (h *ResponseHeader) ContentType() []byte` | Obtain Content-Type | +| `func (h *ResponseHeader) SetContentTypeBytes(contentType []byte)` | Set Content-Type | +| `func (h *ResponseHeader) ContentLength() int` | Obtain Content-Length, which can be a negative value. -1 represents `Transfer-Encoding: chunked`, -2 represents `Transfer-Encoding: identity` | +| `func (h *ResponseHeader) SetContentLength(contentLength int)` | Set Content-Length, which can be a negative value. -1 represents `Transfer-Encoding: chunked`, -2 represents `Transfer-Encoding: identity` | +| `func (h *ResponseHeader) SetContentLengthBytes(contentLength []byte)` | Set Content-Length for type `[]byte`, which can be a negative value. -1 represents `Transfer-Encoding: chunked`, -2 represents `Transfer-Encoding: identity` | +| `func (h *ResponseHeader) CopyTo(dst *ResponseHeader)` | Return a copy of the response header, which can be used when there is competitive access to the response header | +| `func (h *ResponseHeader) GetHeaders() []argsKV` | Return all response headers in the form of key value pairs | +| `func (h *ResponseHeader) VisitAll(f func(key, value []byte))` | Visit all the key values of all headers and execute the f function | +| `func (h *ResponseHeader) Get(key string) string` | Obtain the value of key, concurrency security | +| `func (h *ResponseHeader) GetAll(key string) []string` | Obtain all values of key with type `[]byte` (used to obtain multiple values with the same key), concurrency safety | +| `func (h *ResponseHeader) Peek(key string) []byte` | Obtain a key value of type `[]byte` as key, which is not secure for concurrency, and using `Get` when competing for access | +| `func (h *ResponseHeader) PeekAll(key string) [][]byte` | Obtain all values of type `[]byte` key as key (used to obtain multiple values with the same key), which is not secure for concurrency, and uses `GetAll` when competing for access | +| `func (h *ResponseHeader) Set(key, value string)` | Set the header key value to set a single header for the same key | +| `func (h *ResponseHeader) SetBytesV(key string, value []byte)` | Set the header key value of type `[]byte` to set a single header for the same key | +| `func (h *ResponseHeader) Add(key, value string)` | Set the header key value to set multiple headers for the same key, but the key will overwrite the following headers: Content Type, Content Length, Connection, Cookie, Transfer Encoding, Host, User Agent | +| `func (h *ResponseHeader) AddArgBytes(key, value []byte, noValue bool)` | Add Header key value (different from `Add`, the key must not be normalized and will not undergo special processing when it is Content-Type, Content-Length, Content-Encoding, Connection, Server, Set-Cookie, Transfer-Encoding) | +| `func (h *ResponseHeader) SetArgBytes(key, value []byte, noValue bool)` | Set Header key value (different from `Set`, the key must not be normalized and will not undergo special processing when it is Content-Type, Content-Length, Content-Encoding, Connection, Server, Set-Cookie, Transfer-Encoding) | +| `func (h *ResponseHeader) Del(key string)` | Delete key value pairs with key in the header | +| `func (h *ResponseHeader) DelBytes(key []byte)` | Delete key value pairs with key in the header | +| `func (h *ResponseHeader) AppendBytes(dst []byte) []byte` | Attach the complete header to the dst and return | +| `func (h *ResponseHeader) Header() []byte` | Obtain the complete header of type `[]byte` | +| `func (h *ResponseHeader) PeekLocation() []byte` | Return the value with key `Location` in the header | +| `func (h *ResponseHeader) Cookie(cookie *Cookie) bool` | Fill cookie for the given cookie.Key, and return false if the cookie.Key is missing | +| `func (h *RequestHeader) FullCookie() []byte` | Return the complete cookie as a byte array | +| `func (h *ResponseHeader) SetCookie(cookie *Cookie)` | Set Cookie Key Values | +| `func (h *ResponseHeader) VisitAllCookie(f func(key, value []byte))` | Visit all the key values of all cookies and execute the f function | +| `func (h *ResponseHeader) DelAllCookies()` | Delete all cookies | +| `func (h *ResponseHeader) DelCookie(key string)` | Delete cookie with key in the response header. To delete cookies from the client, use the `DelClientCookie` function | +| `func (h *ResponseHeader) DelCookieBytes(key []byte)` | Delete cookie with key in the response header. To delete cookies from the client, use the `DelClientCookieBytes` function | +| `func (h *ResponseHeader) DelClientCookie(key string)` | Remove the cookie from the client | +| `func (h *ResponseHeader) DelClientCookieBytes(key []byte)` | Remove the cookie from the client | +| `func (h *ResponseHeader) SetConnectionClose(close bool)` | Set the `Connection: close` flag in the response header | +| `func (h *ResponseHeader) ConnectionClose() bool` | Determine if Connection: close is included | +| `func (h *ResponseHeader) ContentEncoding() []byte` | Obtion Content-Encoding | +| `func (h *ResponseHeader) SetContentEncoding(contentEncoding string)` | Set Content-Encoding | +| `func (h *ResponseHeader) SetContentEncodingBytes(contentEncoding []byte)` | Set Content-Encoding | +| `func (h *ResponseHeader) SetCanonical(key, value []byte)` | Set the Header key value, assuming that the key is in canonical form | +| `func (h *ResponseHeader) Server() []byte` | Return the value with key `Server` in the header | +| `func (h *ResponseHeader) SetServerBytes(server []byte)` | Set the key in the header to the value of Server | +| `func (h *ResponseHeader) MustSkipContentLength() bool` | Determine if there is a response body (according to the HTTP/1.1 protocol, there is no response body when the response status codes are 1xx, 204, or 304) | +| `func (h *ResponseHeader) StatusCode() int` | Obtion StatusCode | +| `func (h *ResponseHeader) SetStatusCode(statusCode int)` | Set StatusCode | +| `func (h *ResponseHeader) Len() int` | Return the number of headers | +| `func (h *ResponseHeader) DisableNormalizing()` | Disable the normalization of header name (capitalize the first letter and the first letter after the Em dash) | +| `func (h *ResponseHeader) IsDisableNormalizing() bool` | Whether to disable the normalization of header names, default not disabled | +| `func (h *ResponseHeader) Trailer() *Trailer` | Get Trailer | +| `func (h *ResponseHeader) SetProtocol(p string)` | Set protocol name | +| `func (h *ResponseHeader) GetProtocol() string` | Get protocol name | +| `func (h *ResponseHeader) Reset()` | Reset the response header | +| `func (h *ResponseHeader) ResetSkipNormalize()` | Reset the response header, except for the `disableNormalizing` state | +| `func (h *ResponseHeader) ResetConnectionClose()` | Reset the connectionClose flag to false and delete the Connection Header | ## Render @@ -612,8 +621,8 @@ h.GET("/user", func(c context.Context, ctx *app.RequestContext) { ## Other Functions ```go -func (ctx *RequestContext) Flush() error -func (ctx *RequestContext) GetResponse() (dst *protocol.Response) +func (ctx *RequestContext) Flush() error +func (ctx *RequestContext) GetResponse() (dst *protocol.Response) ``` ### Flush @@ -623,7 +632,7 @@ Brush data into the hijacked Response Writer. (For more information, please refe Function Signature: ```go -func (ctx *RequestContext) Flush() error +func (ctx *RequestContext) Flush() error ``` ### GetResponse diff --git a/content/en/docs/hertz/tutorials/basic-feature/engine.md b/content/en/docs/hertz/tutorials/basic-feature/engine.md index 09b4473ad1..6e903e91bd 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/engine.md +++ b/content/en/docs/hertz/tutorials/basic-feature/engine.md @@ -5,12 +5,11 @@ weight: 1 description: > --- - `Server.Hertz` is the core type of `Hertz`, consisting of `route.Engine` and `signalWaiter`. The important methods for starting, registering routes, registering middleware, and exiting the `Hertz` server are all included in `server.Hertz`. The following is the definition of `server.Hertz`: ```go type Hertz struct { -    *route.Engine +    *route.Engine     // used to receive signal for elegant exit     signalWaiter func (err chan error) error } @@ -20,48 +19,48 @@ type Hertz struct { ## Config -| **Option** | **Default** | **Description** | -| :---- | :---- | :---- | -| WithTransport | network.NewTransporter | Replace the transport | -| WithHostPorts | `:8888` | Specify the listening address and port | -| WithKeepAliveTimeout | 1min | Set the keep-alive time of tcp persistent connection, generally no need to modify it, you should more pay attention to idleTimeout rather than modifying it | -| WithReadTimeout | 3min | The timeout of data reading | -| WithIdleTimeout | 3min | The free timeout of the request link for persistent connection | -| WithMaxRequestBodySize | 4 * 1024 * 1024 | Max body size of a request | -| WithRedirectTrailingSlash | true | Whether to redirect with the / which is at the end of the router automatically. For example: If there is only /foo/ in the router, /foo will be redirected to /foo/. And if there is only /foo in the router, /foo/ will be redirected to /foo | -| WithRemoveExtraSlash | false | RemoveExtraSlash makes the parameter still valid when it contains an extra /. For example, if WithRemoveExtraSlash is true user//xiaoming can match the user/:name router | -| WithUnescapePathValues | true | If true, the request path will be escaped automatically (eg. '%2F' -> '/'). If UseRawPath is false (the default), UnescapePathValues is true, because URI().Path() will be used and it is already escaped. To set WithUnescapePathValues to false, you need to set WithUseRawPath to true | -| WithUseRawPath | false | If true, the original path will be used to match the route | -| WithHandleMethodNotAllowed | false | If true when the current path cannot match any method, the server will check whether other methods are registered with the route of the current path, and if exist other methods, it will respond "Method Not Allowed" and return the status code 405; if not, it will use the handler of NotFound to handle it | -| WithDisablePreParseMultipartForm | false | If true, the multipart form will not be preprocessed. The body can be obtained via ctx.Request.Body() and then can be processed by user | -| WithStreamBody | false | If true, the body will be handled by stream processing | -| WithNetwork | "tcp" | Set the network protocol, optional: tcp,udp,unix(unix domain socket) | -| WithExitWaitTime | 5s | Set the graceful exit time. the Server will stop connection establishment for new requests and set the Connection: Close header for each request after closing. When the set time is reached, Server will to be closed. the Server can be closed early when all connections have been closed | -| WithTLS | nil | Configuring server tls capabilities, For detailed information, please refer to [TLS](/zh/docs/hertz/tutorials/basic-feature/protocol/tls/) | -| WithListenConfig | nil | Set the listener configuration. Can be used to set whether to allow reuse ports, etc.| -| WithALPN | false | Whether to enable ALPN | -| WithTracer | []interface{}{} | Inject tracer implementation, if not inject Tracer, default: close. | -| WithTraceLevel | LevelDetailed | Set trace level | -| WithWriteTimeout | infinite | The timeout of data writing | -| WithRedirectFixedPath | false | If enabled, if the current request path does not match, the server will try to repair the request path and re-match, if the match is successful and the request is a GET request, it will return status code 301 for redirect, other requests will return 308 for redirect | -| WithBasePath | `/` | Set the base path, which must be prefixed and suffixed with `/` | -| WithMaxKeepBodySize | 4 * 1024 * 1024 | Sets the maximum size of the request body and response body to be retained during reclaim. Unit: Byte | -| WithGetOnly | false | If enabled, only GET requests are accepted | -| WithKeepAlive | true | If enabled, use HTTP keepalive | -| WithAltTransport | network.NewTransporter | Set up the alternate transport | -| WithH2C | false | Sets whether H2C is enabled | -| WithReadBufferSize | 4 * 1024 | Set the read buffer size while limiting the HTTP header size | -| WithRegistry | registry.NoopRegistry, nil | Setup registry configuration, service registration information | -| WithAutoReloadRender | false, 0 | Set up the automatic reload rendering configuration | -| WithDisablePrintRoute | false | Sets whether debugPrintRoute is disabled | -| WithOnAccept | nil | Set the callback function when a new connection is accepted but cannot receive data in netpoll. In go net, it will be called before converting tls connection | -| WithOnConnect | nil | Set the onConnect function. It can received data from connection in netpoll. In go net, it will be called after converting tls connection | -| WithDisableHeaderNamesNormalizing|false|Sets whether or not to disable Request and Response Header name normalization (capitalization of the first letter and the first letter after a dash)| +| **Option** | **Default** | **Description** | +| :-------------------------------- | :------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| WithTransport | network.NewTransporter | Replace the transport | +| WithHostPorts | `:8888` | Specify the listening address and port | +| WithKeepAliveTimeout | 1min | Set the keep-alive time of tcp persistent connection, generally no need to modify it, you should more pay attention to idleTimeout rather than modifying it | +| WithReadTimeout | 3min | The timeout of data reading | +| WithIdleTimeout | 3min | The free timeout of the request link for persistent connection | +| WithMaxRequestBodySize | 4 _ 1024 _ 1024 | Max body size of a request | +| WithRedirectTrailingSlash | true | Whether to redirect with the / which is at the end of the router automatically. For example: If there is only /foo/ in the router, /foo will be redirected to /foo/. And if there is only /foo in the router, /foo/ will be redirected to /foo | +| WithRemoveExtraSlash | false | RemoveExtraSlash makes the parameter still valid when it contains an extra /. For example, if WithRemoveExtraSlash is true user//xiaoming can match the user/:name router | +| WithUnescapePathValues | true | If true, the request path will be escaped automatically (eg. '%2F' -> '/'). If UseRawPath is false (the default), UnescapePathValues is true, because URI().Path() will be used and it is already escaped. To set WithUnescapePathValues to false, you need to set WithUseRawPath to true | +| WithUseRawPath | false | If true, the original path will be used to match the route | +| WithHandleMethodNotAllowed | false | If true when the current path cannot match any method, the server will check whether other methods are registered with the route of the current path, and if exist other methods, it will respond "Method Not Allowed" and return the status code 405; if not, it will use the handler of NotFound to handle it | +| WithDisablePreParseMultipartForm | false | If true, the multipart form will not be preprocessed. The body can be obtained via ctx.Request.Body() and then can be processed by user | +| WithStreamBody | false | If true, the body will be handled by stream processing | +| WithNetwork | "tcp" | Set the network protocol, optional: tcp,udp,unix(unix domain socket) | +| WithExitWaitTime | 5s | Set the graceful exit time. the Server will stop connection establishment for new requests and set the Connection: Close header for each request after closing. When the set time is reached, Server will to be closed. the Server can be closed early when all connections have been closed | +| WithTLS | nil | Configuring server tls capabilities, For detailed information, please refer to [TLS](/zh/docs/hertz/tutorials/basic-feature/protocol/tls/) | +| WithListenConfig | nil | Set the listener configuration. Can be used to set whether to allow reuse ports, etc. | +| WithALPN | false | Whether to enable ALPN | +| WithTracer | []interface{}{} | Inject tracer implementation, if not inject Tracer, default: close. | +| WithTraceLevel | LevelDetailed | Set trace level | +| WithWriteTimeout | infinite | The timeout of data writing | +| WithRedirectFixedPath | false | If enabled, if the current request path does not match, the server will try to repair the request path and re-match, if the match is successful and the request is a GET request, it will return status code 301 for redirect, other requests will return 308 for redirect | +| WithBasePath | `/` | Set the base path, which must be prefixed and suffixed with `/` | +| WithMaxKeepBodySize | 4 _ 1024 _ 1024 | Sets the maximum size of the request body and response body to be retained during reclaim. Unit: Byte | +| WithGetOnly | false | If enabled, only GET requests are accepted | +| WithKeepAlive | true | If enabled, use HTTP keepalive | +| WithAltTransport | network.NewTransporter | Set up the alternate transport | +| WithH2C | false | Sets whether H2C is enabled | +| WithReadBufferSize | 4 \* 1024 | Set the read buffer size while limiting the HTTP header size | +| WithRegistry | registry.NoopRegistry, nil | Setup registry configuration, service registration information | +| WithAutoReloadRender | false, 0 | Set up the automatic reload rendering configuration | +| WithDisablePrintRoute | false | Sets whether debugPrintRoute is disabled | +| WithOnAccept | nil | Set the callback function when a new connection is accepted but cannot receive data in netpoll. In go net, it will be called before converting tls connection | +| WithOnConnect | nil | Set the onConnect function. It can received data from connection in netpoll. In go net, it will be called after converting tls connection | +| WithDisableHeaderNamesNormalizing | false | Sets whether or not to disable Request and Response Header name normalization (capitalization of the first letter and the first letter after a dash) | Server Connection limitation: -* If you are using the standard network library, there is no such restriction. -* If netpoll is used, the maximum number of connections is 10000 (this is +- If you are using the standard network library, there is no such restriction. +- If netpoll is used, the maximum number of connections is 10000 (this is the [gopool](https://github.com/bytedance/gopkg/blob/b9c1c36b51a6837cef4c2223e11522e3a647460c/util/gopool/gopool.go#L46)) used at the bottom of netpoll. Yes, the modification method is also very simple, just call the function provided by gopool: `gopool.SetCap(xxx)` (you can call it once in main.go). @@ -289,129 +288,129 @@ Two methods are provided: 1. The user passes in a `io.Reader` through the `ctx.SetBodyStream` function in the handler, and then reads and writes data in blocks in a similar manner to the example code (using channel to control data partitioning and read/write order) **Note that data needs to be written asynchronously**. - If the user knows the total length of the transmitted data in advance, they can pass in the length in the `ctx.SetBodyStream` function for streaming writing, as shown in the example code `/streamWrite1`. - - If the user does not know the total length of the transmitted data in advance, they can pass in -1 in the `ctx.SetBodyStream` function to write the stream in the form of `Transfer-Encoding: chunked`, as shown in the example code `/streamWrite2`. - - Example Code: - - ```go - func main() { - h := server.Default(server.WithHostPorts("127.0.0.1:8080"), server.WithStreamBody(true), server.WithTransport(standard.NewTransporter)) - - h.GET("/streamWrite1", func(c context.Context, ctx *app.RequestContext) { - rw := newChunkReader() - line := []byte("line\r\n") - ctx.SetBodyStream(rw, 500*len(line)) - - go func() { - for i := 1; i <= 500; i++ { - // For each streaming_write, the upload_file prints - rw.Write(line) - fmt.Println(i) - time.Sleep(10 * time.Millisecond) - } - rw.Close() - }() - - go func() { - <-ctx.Finished() - fmt.Println("request process end") - }() - }) - - h.GET("/streamWrite2", func(c context.Context, ctx *app.RequestContext) { - rw := newChunkReader() - // Content-Length may be negative: - // -1 means Transfer-Encoding: chunked. - ctx.SetBodyStream(rw, -1) - - go func() { - for i := 1; i < 1000; i++ { - // For each streaming_write, the upload_file prints - rw.Write([]byte(fmt.Sprintf("===%d===\n", i))) - fmt.Println(i) - time.Sleep(100 * time.Millisecond) - } - rw.Close() - }() - - go func() { - <-ctx.Finished() - fmt.Println("request process end") - }() - }) - - h.Spin() - } - - type ChunkReader struct { - rw bytes.Buffer - w2r chan struct{} - r2w chan struct{} - } - - func newChunkReader() *ChunkReader { - var rw bytes.Buffer - w2r := make(chan struct{}) - r2w := make(chan struct{}) - cr := &ChunkReader{rw, w2r, r2w} - return cr - } - - var closeOnce = new(sync.Once) - - func (cr *ChunkReader) Read(p []byte) (n int, err error) { - for { - _, ok := <-cr.w2r - if !ok { - closeOnce.Do(func() { - close(cr.r2w) - }) - n, err = cr.rw.Read(p) - return - } - - n, err = cr.rw.Read(p) - - cr.r2w <- struct{}{} - - if n == 0 { - continue - } - return - } - } - - func (cr *ChunkReader) Write(p []byte) (n int, err error) { - n, err = cr.rw.Write(p) - cr.w2r <- struct{}{} - <-cr.r2w - return - } - - func (cr *ChunkReader) Close() { - close(cr.w2r) - } - - ``` + If the user knows the total length of the transmitted data in advance, they can pass in the length in the `ctx.SetBodyStream` function for streaming writing, as shown in the example code `/streamWrite1`. + + If the user does not know the total length of the transmitted data in advance, they can pass in -1 in the `ctx.SetBodyStream` function to write the stream in the form of `Transfer-Encoding: chunked`, as shown in the example code `/streamWrite2`. + + Example Code: + + ```go + func main() { + h := server.Default(server.WithHostPorts("127.0.0.1:8080"), server.WithStreamBody(true), server.WithTransport(standard.NewTransporter)) + + h.GET("/streamWrite1", func(c context.Context, ctx *app.RequestContext) { + rw := newChunkReader() + line := []byte("line\r\n") + ctx.SetBodyStream(rw, 500*len(line)) + + go func() { + for i := 1; i <= 500; i++ { + // For each streaming_write, the upload_file prints + rw.Write(line) + fmt.Println(i) + time.Sleep(10 * time.Millisecond) + } + rw.Close() + }() + + go func() { + <-ctx.Finished() + fmt.Println("request process end") + }() + }) + + h.GET("/streamWrite2", func(c context.Context, ctx *app.RequestContext) { + rw := newChunkReader() + // Content-Length may be negative: + // -1 means Transfer-Encoding: chunked. + ctx.SetBodyStream(rw, -1) + + go func() { + for i := 1; i < 1000; i++ { + // For each streaming_write, the upload_file prints + rw.Write([]byte(fmt.Sprintf("===%d===\n", i))) + fmt.Println(i) + time.Sleep(100 * time.Millisecond) + } + rw.Close() + }() + + go func() { + <-ctx.Finished() + fmt.Println("request process end") + }() + }) + + h.Spin() + } + + type ChunkReader struct { + rw bytes.Buffer + w2r chan struct{} + r2w chan struct{} + } + + func newChunkReader() *ChunkReader { + var rw bytes.Buffer + w2r := make(chan struct{}) + r2w := make(chan struct{}) + cr := &ChunkReader{rw, w2r, r2w} + return cr + } + + var closeOnce = new(sync.Once) + + func (cr *ChunkReader) Read(p []byte) (n int, err error) { + for { + _, ok := <-cr.w2r + if !ok { + closeOnce.Do(func() { + close(cr.r2w) + }) + n, err = cr.rw.Read(p) + return + } + + n, err = cr.rw.Read(p) + + cr.r2w <- struct{}{} + + if n == 0 { + continue + } + return + } + } + + func (cr *ChunkReader) Write(p []byte) (n int, err error) { + n, err = cr.rw.Write(p) + cr.w2r <- struct{}{} + <-cr.r2w + return + } + + func (cr *ChunkReader) Close() { + close(cr.w2r) + } + + ``` 2. Users can use the `NewChunkedBodyWriter` method provided under `pkg/protocol/http1/resp/writer` in the handler to hijack the response writer, and then use the `ctx.Write` function to write the partitioned data to the body and immediately send it to the client using the `ctx.Flush` function. - Example Code: + Example Code: - ```go - h.GET("/flush/chunk", func(c context.Context, ctx *app.RequestContext) { - // Hijack the writer of response - ctx.Response.HijackWriter(resp.NewChunkedBodyWriter(&ctx.Response, ctx.GetWriter())) + ```go + h.GET("/flush/chunk", func(c context.Context, ctx *app.RequestContext) { + // Hijack the writer of response + ctx.Response.HijackWriter(resp.NewChunkedBodyWriter(&ctx.Response, ctx.GetWriter())) - for i := 0; i < 10; i++ { - ctx.Write([]byte(fmt.Sprintf("chunk %d: %s", i, strings.Repeat("hi~", i)))) // nolint: errcheck - ctx.Flush() // nolint: errcheck - time.Sleep(200 * time.Millisecond) - } - }) - ``` + for i := 0; i < 10; i++ { + ctx.Write([]byte(fmt.Sprintf("chunk %d: %s", i, strings.Repeat("hi~", i)))) // nolint: errcheck + ctx.Flush() // nolint: errcheck + time.Sleep(200 * time.Millisecond) + } + }) + ``` **The difference between these two methods: the first method sends the data to the client in blocks after executing the handler logic, and the second method can send the partitioned data out in the handler logic.** diff --git a/content/en/docs/hertz/tutorials/basic-feature/error-handle.md b/content/en/docs/hertz/tutorials/basic-feature/error-handle.md index 9a2d9b2479..0c3151b205 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/error-handle.md +++ b/content/en/docs/hertz/tutorials/basic-feature/error-handle.md @@ -4,7 +4,6 @@ date: 2023-04-18 weight: 10 keywords: ["Error Handle", "Custom Error"] description: "The error handling function provided by Hertz." - --- ## Error @@ -19,14 +18,14 @@ type Error struct { } ``` - `Err` is standard error, `Type` is the type of error, `Meta` is the metadata. +`Err` is standard error, `Type` is the type of error, `Meta` is the metadata. ### Error Type In order to handle errors more efficiently, Hertz has predefined the following error types: ```go -// Error in binding process +// Error in binding process ErrorTypeBind ErrorType = 1 << iota // Error in rendering process ErrorTypeRender @@ -78,14 +77,14 @@ func NewPrivatef(format string, v ...interface{}) *Error { ### Relevant functions -| signature | description | -| -------------------------------- | ----------------------------------------------------------- | -| SetType(flags ErrorType) *Error | set the `ErrorType` to the given `flags` | -| Error() string | implement the `error` interface | -| Unwrap() error | throw an error | -| SetMeta(data interface{}) *Error | set the `Meta` to the given `data` | -| IsType(flags ErrorType) bool | determine whether the `ErrorType` matches the given `flags` | -| JSON() interface{} | convert the error to a `json` object | +| signature | description | +| --------------------------------- | ----------------------------------------------------------- | +| SetType(flags ErrorType) \*Error | set the `ErrorType` to the given `flags` | +| Error() string | implement the `error` interface | +| Unwrap() error | throw an error | +| SetMeta(data interface{}) \*Error | set the `Meta` to the given `data` | +| IsType(flags ErrorType) bool | determine whether the `ErrorType` matches the given `flags` | +| JSON() interface{} | convert the error to a `json` object | ## ErrorChain @@ -93,13 +92,13 @@ In addition to the conventions for error definition, the framework also provides ### Relevant functions -| signature | description | -| -------------------------------- | ------------------------------------------------------------ | -| String() string | return a human-readable text for displaying all errors | -| Errors() []string | convert the `ErrorChain` to an array of standard errors | +| signature | description | +| -------------------------------- | ------------------------------------------------------------------ | +| String() string | return a human-readable text for displaying all errors | +| Errors() []string | convert the `ErrorChain` to an array of standard errors | | ByType(typ ErrorType) ErrorChain | return the corresponding sub-`ErrorChain` for the given error type | -| Last() *Error | return the last error | -| JSON() interface{} | convert all errors to a `json` object | +| Last() \*Error | return the last error | +| JSON() interface{} | convert all errors to a `json` object | ### How To Use diff --git a/content/en/docs/hertz/tutorials/basic-feature/graceful-shutdown.md b/content/en/docs/hertz/tutorials/basic-feature/graceful-shutdown.md index 43d780276b..e00c3a8886 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/graceful-shutdown.md +++ b/content/en/docs/hertz/tutorials/basic-feature/graceful-shutdown.md @@ -4,7 +4,6 @@ date: 2022-05-23 weight: 11 keywords: ["Graceful Shutdown"] description: "The graceful shutdown function provided by Hertz when stopping service." - --- Hertz supports graceful shutdown, which is executed as follows: diff --git a/content/en/docs/hertz/tutorials/basic-feature/hooks.md b/content/en/docs/hertz/tutorials/basic-feature/hooks.md index 37476ee1a1..e675fd4175 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/hooks.md +++ b/content/en/docs/hertz/tutorials/basic-feature/hooks.md @@ -4,7 +4,6 @@ date: 2022-10-16 weight: 14 keywords: ["Hooks", "StartHook", "ShutdownHook", "OnAccept", "OnConnect"] description: "The hooks function provided by Hertz." - --- **Hook** is a generic concept that indicates the action that accompanies an event when it is triggered. @@ -35,7 +34,7 @@ package main import ( "context" - + "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/cloudwego/hertz/pkg/common/hlog" @@ -67,7 +66,7 @@ func main() { } ``` -Note: After triggering startup, The logs of the three `StartHook` functions will be printed in the terminal **in order**. +Note: After triggering startup, The logs of the three `StartHook` functions will be printed in the terminal **in order**. ```shell main.go:17: [Info] run the first start hook @@ -141,7 +140,7 @@ package main import ( "context" "time" - + "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/cloudwego/hertz/pkg/common/hlog" diff --git a/content/en/docs/hertz/tutorials/basic-feature/json.md b/content/en/docs/hertz/tutorials/basic-feature/json.md index b2ae308195..1e313228a3 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/json.md +++ b/content/en/docs/hertz/tutorials/basic-feature/json.md @@ -3,7 +3,13 @@ title: "JSON Marshal Library" linkTitle: "JSON Marshal Library" date: 2023-08-03 weight: 19 -keywords: ["JSON Marshal", "Sonic", "Conditional Compilation", "Bringing Your Own JSON Marshal Library"] +keywords: + [ + "JSON Marshal", + "Sonic", + "Conditional Compilation", + "Bringing Your Own JSON Marshal Library", + ] description: "The JSON Marshal library and customization capabilities used by Hertz." --- @@ -27,7 +33,7 @@ If Sonic does not meet your needs, you may provide your own implementation by ca Hertz supports conditional compilation to control the actual json library used, you can use `-tags stdjson` to choose to use the standard library. ```go -go build -tags stdjson +go build -tags stdjson ``` ## Sonic related issues diff --git a/content/en/docs/hertz/tutorials/basic-feature/middleware/_index.md b/content/en/docs/hertz/tutorials/basic-feature/middleware/_index.md index 4c9bfbf8eb..33650c66b3 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/middleware/_index.md +++ b/content/en/docs/hertz/tutorials/basic-feature/middleware/_index.md @@ -2,25 +2,31 @@ title: "Middleware Overview" date: 2022-05-23 weight: 6 -keywords: ["Middleware", "Server-side middleware", "Client-side middleware", "routing level"] +keywords: + [ + "Middleware", + "Server-side middleware", + "Client-side middleware", + "routing level", + ] description: "Middleware Overview." - --- There are various types of Hertz middleware, which are simply divided into two categories. - - Server-side middleware - - Client-side middleware +- Server-side middleware +- Client-side middleware ## Server-side middleware Server-side middleware is a function in the HTTP request-response cycle that provides a convenient mechanism for inspecting and filtering HTTP requests entering your application, such as logging each request or enabling CORS. -|![middleware](/img/docs/hertz_middleware.png )| -|:--:| -|Figure 1: middleware call chain| +| ![middleware](/img/docs/hertz_middleware.png) | +| :-------------------------------------------: | +| Figure 1: middleware call chain | Middleware can perform tasks before or after passing the request deeper into the application: + - Middleware can be executed before the request reaches business processing, such as performing identity authentication and authorization authentication. When the middleware only has pre-handle logic and there is no requirement to be in a function call stack with real handler, the `.Next` can be omitted. - Middleware can also be executed after business processing has been performed, such as logging response times and recovering from a panic. If there is other processing logic (post-handle) after the business handler, or there is a strong requirement for the function call chain (stack), then the `.Next` must be called explicitly, see middleware C in Figure 1. @@ -147,12 +153,13 @@ Hertz provides frequently-used middlewares such as BasicAuth, CORS, JWT etc., mo ## Client-side Middleware Client-side middleware can be executed before the request is made or after the response is obtained: + - Middleware can be executed before the request is sent, such as adding a signature or other fields to the request. - Middleware can also be executed after receiving the response, such as modifying the response result to adapt to the business logic. ### Implement customized middleware -The middleware implementation on the Client side is different from that on the Server side. The Client side cannot get the index of the middleware to increase, so the Client middleware uses nested functions to build the middleware in advance. When implementing client-side customized middleware, you can refer to the following code. +The middleware implementation on the Client side is different from that on the Server side. The Client side cannot get the index of the middleware to increase, so the Client middleware uses nested functions to build the middleware in advance. When implementing client-side customized middleware, you can refer to the following code. ```go func MyMiddleware(next client.Endpoint) client.Endpoint { @@ -230,7 +237,7 @@ func main() { ### RequestContext related operations -When implementing server-side middleware, the `RequestContext` related operation is usually used, as shown in [RequestContext](/docs/hertz/tutorials/basic-feature/context/). +When implementing server-side middleware, the `RequestContext` related operation is usually used, as shown in [RequestContext](/docs/hertz/tutorials/basic-feature/context/). ### Handler related operations @@ -239,6 +246,7 @@ A server-side middleware is a handler, and the related operations of the handler ### Quick termination of server middleware The server-side middleware will be executed in the order defined, if you want to terminate the middleware call quickly, you can use the following methods, noting that **the current middleware will still execute**. + - `c.Abort()`:terminate subsequent calls - `c.AbortWithMsg(msg string, statusCode int)`:terminates subsequent calls and sets the body and status code for the Response -- `c.AbortWithStatus(code int)`:terminates subsequent calls and sets the status code \ No newline at end of file +- `c.AbortWithStatus(code int)`:terminates subsequent calls and sets the status code diff --git a/content/en/docs/hertz/tutorials/basic-feature/middleware/basic-auth.md b/content/en/docs/hertz/tutorials/basic-feature/middleware/basic-auth.md index 50722def81..79831ce43d 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/middleware/basic-auth.md +++ b/content/en/docs/hertz/tutorials/basic-feature/middleware/basic-auth.md @@ -4,7 +4,6 @@ date: 2022-10-13 weight: 2 keywords: ["HTTP", "Basic Auth"] description: "Hertz provides an implementation of Basic Auth." - --- In HTTP, Basic Access Authentication is a form of login authentication that allows web browsers or other client programs to provide credentials in the form of a username and password upon request. @@ -59,8 +58,8 @@ In the **Example** above, only the base config function `BasicAuth` is used, and **Note:** `BasicAuth` is a wrapper around `BasicAuthForRealm` and provides default configuration options. | Attribute | Description | -|-----------|-------------------------------------------------------------------------------------------------------------------| -| accounts | `Accounts` is a defined type of `map[string]string`, store the username and password as key-value pairs. | +| --------- | ----------------------------------------------------------------------------------------------------------------- | +| accounts | `Accounts` is a defined type of `map[string]string`, store the username and password as key-value pairs. | | realm | Name of realm, the default value is `Authorization Required`. | | userKey | The key corresponding to the username which set in the context after authentication, the default value is `user`. | diff --git a/content/en/docs/hertz/tutorials/basic-feature/middleware/cache.md b/content/en/docs/hertz/tutorials/basic-feature/middleware/cache.md index c1dacf6fcc..2ba2ae35c3 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/middleware/cache.md +++ b/content/en/docs/hertz/tutorials/basic-feature/middleware/cache.md @@ -4,7 +4,6 @@ date: 2023-02-25 weight: 15 keywords: ["HTTP Response", "Cache"] description: "Hertz provides the adaptation of cache, supporting multi-backend." - --- cache is a middleware for caching HTTP Responses, which helps to improve the concurrent access capacity of the Server. Hertz also provides the [adaptation](https://github.com/hertz-contrib/cache) of cache, supporting multi-backend, referring to [gin-cache](https://github.com/chenyahui/gin-cache). @@ -194,16 +193,16 @@ func main() { ### Generic Configuration -| Configuration | Default | Description | -| :---------------------------- | ------- | ------------------------------------------------------------ | -| WithOnHitCache | nil | Used to set the callback function after a cache hits | -| WithOnMissCache | nil | Used to set the callback function for cache misses | -| WithBeforeReplyWithCache | nil | Used to set the callback function before returning the cached response | +| Configuration | Default | Description | +| :---------------------------- | ------- | -------------------------------------------------------------------------------------------- | +| WithOnHitCache | nil | Used to set the callback function after a cache hits | +| WithOnMissCache | nil | Used to set the callback function for cache misses | +| WithBeforeReplyWithCache | nil | Used to set the callback function before returning the cached response | | WithOnShareSingleFlight | nil | Used to set the callback function when the result of a SingleFlight is shared by the request | -| WithSingleFlightForgetTimeout | 0 | Used to set the timeout for SingleFlight | -| WithPrefixKey | "" | Used to set the prefix of the cache response key | -| WithoutHeader | false | Used to set whether response headers need to be cached | -| WithCacheStrategyByRequest | nil | Used to set custom caching policies | +| WithSingleFlightForgetTimeout | 0 | Used to set the timeout for SingleFlight | +| WithPrefixKey | "" | Used to set the prefix of the cache response key | +| WithoutHeader | false | Used to set whether response headers need to be cached | +| WithCacheStrategyByRequest | nil | Used to set custom caching policies | ### WithCacheStrategyByRequest @@ -237,7 +236,7 @@ func main() { h.GET("/hello", func(ctx context.Context, c *app.RequestContext) { c.String(http.StatusOK, "hello world") }) - + h.Spin() } ``` @@ -398,7 +397,7 @@ func main() { h.GET("/hello", func(ctx context.Context, c *app.RequestContext) { c.String(http.StatusOK, "hello world") }) - + h.Spin() } ``` @@ -440,7 +439,7 @@ func main() { h.GET("/hello", func(ctx context.Context, c *app.RequestContext) { c.String(http.StatusOK, "hello world") }) - + h.Spin() } ``` diff --git a/content/en/docs/hertz/tutorials/basic-feature/middleware/casbin.md b/content/en/docs/hertz/tutorials/basic-feature/middleware/casbin.md index 44549f2be6..aefbea2fc3 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/middleware/casbin.md +++ b/content/en/docs/hertz/tutorials/basic-feature/middleware/casbin.md @@ -12,7 +12,7 @@ According to the user's use scenario, we provide [Casbin Middleware](https://git ## Install -``` shell +```shell go get github.com/hertz-contrib/casbin ``` @@ -30,7 +30,7 @@ package main import ( "context" "log" - + "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/hertz-contrib/casbin" @@ -40,7 +40,7 @@ import ( func main() { h := server.Default() - + // using sessions to store user info. store := cookie.NewStore([]byte("secret")) h.Use(sessions.New("session", store)) @@ -48,11 +48,11 @@ func main() { if err != nil { log.Fatal(err) } - + h.POST("/login", func(ctx context.Context, c *app.RequestContext) { // verify username and password. // ... - + // store username (casbin subject) in session session := sessions.Default(c) session.Set("name", "alice") @@ -62,15 +62,15 @@ func main() { } c.String(200, "you login successfully") }) - + h.GET("/book", auth.RequiresPermissions("book:read", casbin.WithLogic(casbin.AND)), func(ctx context.Context, c *app.RequestContext) { c.String(200, "you read the book successfully") }) - + h.POST("/book", auth.RequiresRoles("user", casbin.WithLogic(casbin.AND)), func(ctx context.Context, c *app.RequestContext) { c.String(200, "you posted a book successfully") }) - + h.Spin() } @@ -131,7 +131,7 @@ func main() { #### NewCasbinMiddlewareFromEnforcer -You need to provide [enforcer](https://casbin.org/docs/enforcers) and `LookupHandler` (handler that get subject) to initialize middleware. +You need to provide [enforcer](https://casbin.org/docs/enforcers) and `LookupHandler` (handler that get subject) to initialize middleware. The function signature is as follows: @@ -158,7 +158,7 @@ func main() { if err != nil{ log.Fatal(err) } - + casbinMiddleware, err := casbin.NewCasbinMiddlewareFromEnforcer(enforcer, exampleLookupHandler) if err != nil { log.Fatal(err) @@ -183,29 +183,29 @@ parameters descriptions is as follows: - **expression** - expression has one or more params, each param is divided by space, the expression format is related to `Logic` (see option description), + expression has one or more params, each param is divided by space, the expression format is related to `Logic` (see option description), - the calculated final value of the expression is either **True** or **False**, **True** represents for has passed casbin middleware, + the calculated final value of the expression is either **True** or **False**, **True** represents for has passed casbin middleware, - **False** represents for has not passed casbin middleware. + **False** represents for has not passed casbin middleware. - If `Logic` is **AND** or **OR**, the format is: + If `Logic` is **AND** or **OR**, the format is: - `"var 1 var2 var3 var4"`, like `"book:read book:write"` + `"var 1 var2 var3 var4"`, like `"book:read book:write"` - If `Logic` is **CUSTOM**, the format is : + If `Logic` is **CUSTOM**, the format is : - `"var1 opr1 var2 opr2 var3"` like `"book:read && book:write || book:all"` + `"var1 opr1 var2 opr2 var3"` like `"book:read && book:write || book:all"` - **opts** - | Option | Description | Default | - | ------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | - | `WithLogic` | `Logic` is the logical operation (**AND**/**OR**/**CUSTOM**) used in permission checks that multiple permissions or roles are specified | `AND` | - | `WithPermissionParser` | `PermissionParserFunc` is used for parsing the permission to extract object and action usually | `PermissionParserWithSeparator(":")` | - | `WithPermissionParserSeparator` | `PermissionParserSeparator` is used to set separator that divide permission to object and action usually | `:` | - | `WithUnauthorized` | `Unauthorized` defined the response body for unauthorized responses | `func(ctx context.Context, c *app.RequestContext) { c.AbortWithStatus(consts.StatusUnauthorized) }` | - | `WithForbidden` | `Forbidden` defines the response body for forbidden responses | `func(ctx context.Context, c *app.RequestContext) { c.AbortWithStatus(consts.StatusForbidden) }` | + | Option | Description | Default | + | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | + | `WithLogic` | `Logic` is the logical operation (**AND**/**OR**/**CUSTOM**) used in permission checks that multiple permissions or roles are specified | `AND` | + | `WithPermissionParser` | `PermissionParserFunc` is used for parsing the permission to extract object and action usually | `PermissionParserWithSeparator(":")` | + | `WithPermissionParserSeparator` | `PermissionParserSeparator` is used to set separator that divide permission to object and action usually | `:` | + | `WithUnauthorized` | `Unauthorized` defined the response body for unauthorized responses | `func(ctx context.Context, c *app.RequestContext) { c.AbortWithStatus(consts.StatusUnauthorized) }` | + | `WithForbidden` | `Forbidden` defines the response body for forbidden responses | `func(ctx context.Context, c *app.RequestContext) { c.AbortWithStatus(consts.StatusForbidden) }` | #### RequiresPermission @@ -225,7 +225,7 @@ like: r = sub, dom, obj, act ``` -when use default `PermissionParser`, **expression** format should be like `"book:read"`. +when use default `PermissionParser`, **expression** format should be like `"book:read"`. like: @@ -250,19 +250,19 @@ when user has `book:read` permission, func main(){ ... h := server.Default() - + m, err := casbin.NewCasbinMiddleware("example/config/model.conf", "example/config/policy.csv", subjectFromSession) if err != nil { log.Fatal(err) } - + h.GET("/book", m.RequiresPermissions("book:read"), // passed func(ctx context.Context, c *app.RequestContext) { c.String(200, "you read the book successfully") }, ) - + h.GET("/book", m.RequiresPermissions("book:read book:write"), // not passed func(ctx context.Context, c *app.RequestContext) { @@ -291,26 +291,26 @@ when user has role of **user** and **reader**, func main(){ ... h := server.Default() - + m, err := casbin.NewCasbinMiddleware("example/config/model.conf", "example/config/policy.csv", subjectFromSession) if err != nil { log.Fatal(err) } - + h.POST("/book", auth.RequiresRoles("user"), // passed func(ctx context.Context, c *app.RequestContext) { c.String(200, "you posted a book successfully") }, ) - + h.POST("/book", auth.RequiresRoles("user reader"), // passed func(ctx context.Context, c *app.RequestContext) { c.String(200, "you posted a book successfully") }, ) - + h.POST("/book", auth.RequiresRoles("user reader admin"), // not passed func(ctx context.Context, c *app.RequestContext) { @@ -347,7 +347,7 @@ const ( **AND** -all variables in `expression` will perform **Logic AND** operation. +all variables in `expression` will perform **Logic AND** operation. Sample code: @@ -357,19 +357,19 @@ when user has `book:read` permission, func main(){ ... h := server.Default() - + m, err := casbin.NewCasbinMiddleware("example/config/model.conf", "example/config/policy.csv", subjectFromSession) if err != nil { log.Fatal(err) } - + h.GET("/book", m.RequiresPermissions("book:read", casbin.WithLogic(casbin.AND)), // passed func(ctx context.Context, c *app.RequestContext) { c.String(200, "you read the book successfully") }, ) - + h.GET("/book", m.RequiresPermissions("book:read book:write", casbin.WithLogic(casbin.AND)), // not passed func(ctx context.Context, c *app.RequestContext) { @@ -382,7 +382,7 @@ func main(){ **OR** -all variables in `expression` will perform **Logical OR** operation. +all variables in `expression` will perform **Logical OR** operation. Sample code: @@ -392,19 +392,19 @@ when user has `book:read` permission, func main(){ ... h := server.Default() - + m, err := casbin.NewCasbinMiddleware("example/config/model.conf", "example/config/policy.csv", subjectFromSession) if err != nil { log.Fatal(err) } - + h.GET("/book", m.RequiresPermissions("book:read", casbin.WithLogic(casbin.OR)), // passed func(ctx context.Context, c *app.RequestContext) { c.String(200, "you read the book successfully") }, ) - + h.GET("/book", m.RequiresPermissions("book:read book:and", casbin.WithLogic(casbin.OR)), // not passed func(ctx context.Context, c *app.RequestContext) { @@ -431,33 +431,33 @@ when user has `book:read` permission, func main(){ ... h := server.Default() - + m, err := casbin.NewCasbinMiddleware("example/config/model.conf", "example/config/policy.csv", subjectFromSession) if err != nil { log.Fatal(err) } - + h.GET("/book", m.RequiresPermissions("book:read", casbin.WithLogic(casbin.CUSTOM)), // passed func(ctx context.Context, c *app.RequestContext) { c.String(200, "you read the book successfully") }, ) - + h.GET("/book", m.RequiresPermissions("book:read && book:write", casbin.WithLogic(casbin.CUSTOM)), // not passed func(ctx context.Context, c *app.RequestContext) { c.String(200, "you read the book successfully") }, ) - + h.GET("/book", m.RequiresPermissions("book:read || book:write", casbin.WithLogic(casbin.CUSTOM)), // passed func(ctx context.Context, c *app.RequestContext) { c.String(200, "you read the book successfully") }, ) - + h.GET("/book", m.RequiresPermissions("!book:read", casbin.WithLogic(casbin.CUSTOM)), // not passed func(ctx context.Context, c *app.RequestContext) { @@ -484,12 +484,12 @@ Sample code: func main(){ ... h := server.Default() - + m, err := casbin.NewCasbinMiddleware("example/config/model.conf", "example/config/policy.csv", subjectFromSession) if err != nil { log.Fatal(err) } - + h.GET("/book", m.RequiresPermissions("book-read", casbin.WithPermissionParser(func(str string) []string { @@ -520,12 +520,12 @@ Sample code: func main(){ ... h := server.Default() - + m, err := casbin.NewCasbinMiddleware("example/config/model.conf", "example/config/policy.csv", subjectFromSession) if err != nil { log.Fatal(err) } - + h.GET("/book", m.RequiresPermissions("book-read", casbin.WithPermissionParserSeparator("-"), @@ -554,12 +554,12 @@ Sample code: func main(){ ... h := server.Default() - + m, err := casbin.NewCasbinMiddleware("example/config/model.conf", "example/config/policy.csv", subjectFromSession) if err != nil { log.Fatal(err) } - + h.GET("/book", m.RequiresPermissions("book:read", casbin.WithUnauthorized(func(c context.Context, ctx *app.RequestContext) { @@ -590,12 +590,12 @@ Sample code: func main(){ ... h := server.Default() - + m, err := casbin.NewCasbinMiddleware("example/config/model.conf", "example/config/policy.csv", subjectFromSession) if err != nil { log.Fatal(err) } - + h.GET("/book", m.RequiresPermissions("book:read", casbin.WithForbidden(func(c context.Context, ctx *app.RequestContext) { diff --git a/content/en/docs/hertz/tutorials/basic-feature/middleware/cors.md b/content/en/docs/hertz/tutorials/basic-feature/middleware/cors.md index 77f57a17a8..fdfea99242 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/middleware/cors.md +++ b/content/en/docs/hertz/tutorials/basic-feature/middleware/cors.md @@ -4,7 +4,6 @@ date: 2022-05-21 weight: 1 keywords: ["CORS"] description: "Hertz provides implementation of CORS middleware." - --- The CORS (Cross-Origin Resource Sharing) mechanism allows a server to identify any origin other than its own so that browsers can access and load those resources. @@ -68,7 +67,7 @@ Hertz allows clients to access resources across origins through the use of cors Only part of the optional parameters are configured in the above **Example**, the full list of parameters for `Config` is as follows: | Parameter | Introduction | -| ---------------------- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | AllowAllOrigins | The property used to allow clients from any origin to access server-side resources, the default value is `false` | | AllowOrigins | The property used to set the list of origins a cross-domain request can be executed from, the default value is `[]` | | AllowOriginFunc | The property used to set a custom function to validate the origin, if this option is set, the content of `AllowOrigins` is ignored | @@ -77,10 +76,10 @@ Only part of the optional parameters are configured in the above **Example**, th | AllowCredentials | The property indicates whether the request can include user credentials like cookies, HTTP authentication, or client-side SSL certificates, the default value is `false` | | ExposeHeaders | The property used to indicate which headers are safe to expose to the API of a CORS API specification, the default value is `[]` | | MaxAge | The property used to set how long (in seconds) the results of a preflight request can be cached | -| AllowWildcard | The property used to allow to add of origins like `http://some-domain/*`, `https://api.*`, or `http://some.*.subdomain.com`, the default value is `false` | +| AllowWildcard | The property used to allow to add of origins like `http://some-domain/*`, `https://api.*`, or `http://some.*.subdomain.com`, the default value is `false` | | AllowBrowserExtensions | The property used to allow usage of popular browser extensions schemas, the default value is `false` | | AllowWebSockets | The property used to allow usage of WebSocket protocol, the default value is `false` | -| AllowFiles | The property used to allow usage of `file://` schema (dangerous!) use it only when you 100% sure it's needed, the default value is `false` | +| AllowFiles | The property used to allow usage of `file://` schema (dangerous!) use it only when you 100% sure it's needed, the default value is `false` | ### AllowAllOrigins diff --git a/content/en/docs/hertz/tutorials/basic-feature/middleware/csrf.md b/content/en/docs/hertz/tutorials/basic-feature/middleware/csrf.md index 07e7381cb9..20ce87d391 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/middleware/csrf.md +++ b/content/en/docs/hertz/tutorials/basic-feature/middleware/csrf.md @@ -4,7 +4,6 @@ date: 2022-12-6 weight: 12 keywords: ["CSRF", "cross-site request forgery attacks"] description: "Hertz provides CSRF middleware to help you prevent cross-site request forgery attacks." - --- Cross-site request forgery (CSRF) is a method of attack that holds a user hostage to perform an unintended action on a currently logged-in Web application. @@ -13,7 +12,7 @@ Hertz provides [CSRF](https://github.com/hertz-contrib/csrf) middleware to help ## Install -``` shell +```shell go get github.com/hertz-contrib/csrf ``` @@ -179,7 +178,7 @@ import ( "context" "fmt" "net/http" - + "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/hertz-contrib/csrf" diff --git a/content/en/docs/hertz/tutorials/basic-feature/middleware/etag.md b/content/en/docs/hertz/tutorials/basic-feature/middleware/etag.md index f3eda6096c..7feb8d5069 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/middleware/etag.md +++ b/content/en/docs/hertz/tutorials/basic-feature/middleware/etag.md @@ -4,7 +4,6 @@ date: 2023-02-11 weight: 14 keywords: ["ETag"] description: "Hertz provides Etag middleware that can operate on `ETag`." - --- The `ETag` (or entity tag) HTTP response header is an identifier for a specific version of a resource. It lets caches be more efficient and save bandwidth, as a web server does not need to resend a full response if the content was not changed. Additionally, etags help to prevent simultaneous updates of a resource from overwriting each other ("mid-air collisions"). @@ -50,11 +49,11 @@ func main() { ## Configuration -| Configuration | Default | Description | -|------------|---|------------------------------------| -| WithWeak | false | Enable weak validator | -| WithNext | nil | Defines a function to skip etag middleware when return is true | -|WithGenerator | nil | Custom etag generation logic | +| Configuration | Default | Description | +| ------------- | ------- | -------------------------------------------------------------- | +| WithWeak | false | Enable weak validator | +| WithNext | nil | Defines a function to skip etag middleware when return is true | +| WithGenerator | nil | Custom etag generation logic | ### WithWeak @@ -97,7 +96,7 @@ func main() { Function Signature: ```go -func WithNext(next NextFunc) Option +func WithNext(next NextFunc) Option ``` Sample Code: diff --git a/content/en/docs/hertz/tutorials/basic-feature/middleware/gzip.md b/content/en/docs/hertz/tutorials/basic-feature/middleware/gzip.md index 0c0451c2af..5df23e7c86 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/middleware/gzip.md +++ b/content/en/docs/hertz/tutorials/basic-feature/middleware/gzip.md @@ -4,7 +4,6 @@ date: 2022-10-19 weight: 4 keywords: ["Gzip", "Compress"] description: "Hertz provides an implementation of Gzip." - --- In HTTP, GNUzip(Gzip) compression coding is a way to optimize the performance of Web applications, and Hertz also provides an [implementation](https://github.com/hertz-contrib/gzip) of Gzip. diff --git a/content/en/docs/hertz/tutorials/basic-feature/middleware/i18n.md b/content/en/docs/hertz/tutorials/basic-feature/middleware/i18n.md index fcf86cf996..76e4668d46 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/middleware/i18n.md +++ b/content/en/docs/hertz/tutorials/basic-feature/middleware/i18n.md @@ -3,8 +3,7 @@ title: "Internationalization" date: 2022-09-15 weight: 5 keywords: ["Internationalization", "i18n"] -description: "Hertz provides the middleware extension for internationalization (i18n)." - +description: "Hertz provides the middleware extension for internationalization (i18n)." --- Hertz provides the [middleware extension](https://github.com/hertz-contrib/i18n) for internationalization (i18n), which references Gin's [implementation](https://github.com/gin-contrib/i18n). @@ -189,14 +188,14 @@ func main() { **Configuration item** -| Configuration items | Type | Default value | Description | -| :------------------ | ------------------ | -------------------------------------------------------- | ------------------------------------------------------------ | -| DefaultLanguage | language.Tag | language.English | Default conversion language type | -| FormatBundleFile | string | "yaml" | Convert file template types,For example yaml, json | -| AcceptLanguage | []language.Tag | []language.Tag{defaultLanguage,language.Chinese} | Receiving conversion type | -| RootPath | string | defaultRootPath | Template file directory | -| UnmarshalFunc | i18n.UnmarshalFunc | yaml.Unmarshal | Template file decoding functions,For example: yaml.Unmarshal | -| Loader | Loader | LoaderFunc(ioutil.ReadFile) | File reading functions, For example : LoaderFunc(ioutil.ReadFile) | +| Configuration items | Type | Default value | Description | +| :------------------ | ------------------ | ------------------------------------------------ | ----------------------------------------------------------------- | +| DefaultLanguage | language.Tag | language.English | Default conversion language type | +| FormatBundleFile | string | "yaml" | Convert file template types,For example yaml, json | +| AcceptLanguage | []language.Tag | []language.Tag{defaultLanguage,language.Chinese} | Receiving conversion type | +| RootPath | string | defaultRootPath | Template file directory | +| UnmarshalFunc | i18n.UnmarshalFunc | yaml.Unmarshal | Template file decoding functions,For example: yaml.Unmarshal | +| Loader | Loader | LoaderFunc(ioutil.ReadFile) | File reading functions, For example : LoaderFunc(ioutil.ReadFile) | ### WithGetLangHandle diff --git a/content/en/docs/hertz/tutorials/basic-feature/middleware/jwt.md b/content/en/docs/hertz/tutorials/basic-feature/middleware/jwt.md index 3af0e89314..c882e430d3 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/middleware/jwt.md +++ b/content/en/docs/hertz/tutorials/basic-feature/middleware/jwt.md @@ -4,7 +4,6 @@ date: 2022-06-09 weight: 3 keywords: ["JWT authentication", "JSON Web Token", "JWT"] description: "Hertz provides an implementation of JWT." - --- JSON Web Token (JWT) is a lightweight authentication specification that allows us to use JWT to deliver secure and reliable information between users and servers. Essentially a token, it is a compact security method for passing between two sides of network communication. @@ -155,7 +154,7 @@ Hertz provides `jwt` checks for routed requests by using middleware. Custom conf In the **Example** above, only **two necessary** custom configurations are passed in. More common configurations for the `HertzJWTMiddleware` are as follows: | Parameter | Introduction | -| :---------------------------- |:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| :---------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `Realm` | The property used to set the name of the realm, the default value is `hertz jwt` | | `SigningAlgorithm` | The property used to set the signature algorithm, which can be HS256, HS384, HS512, RS256, RS384, or RS512, etc. The default value is `HS256` | | `Key` | The property used to set the signature key (required configuration) | diff --git a/content/en/docs/hertz/tutorials/basic-feature/middleware/keyauth.md b/content/en/docs/hertz/tutorials/basic-feature/middleware/keyauth.md index 76c13e6c04..01e7492b0f 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/middleware/keyauth.md +++ b/content/en/docs/hertz/tutorials/basic-feature/middleware/keyauth.md @@ -4,7 +4,6 @@ date: 2022-09-22 weight: 7 keywords: ["KeyAuth", "token authentication"] description: "Hertz provides the keyauth extension to help users achieve `token` authentication." - --- Hertz provides the [keyauth](https://github.com/hertz-contrib/keyauth) extension to help users achieve `token` authentication. The implementation of the [keyauth](https://github.com/hertz-contrib/keyauth) extension references the [Fiber](https://github.com/gofiber/fiber) and [Echo](https://github.com/labstack/echo) implementation. diff --git a/content/en/docs/hertz/tutorials/basic-feature/middleware/paseto.md b/content/en/docs/hertz/tutorials/basic-feature/middleware/paseto.md index fd043e25fa..b7a6c9e18f 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/middleware/paseto.md +++ b/content/en/docs/hertz/tutorials/basic-feature/middleware/paseto.md @@ -80,14 +80,14 @@ func main() { ## Options -| Option | Default | Description | -|----------------|----------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------| -| Next | [nil](https://github.com/hertz-contrib/paseto/blob/main/option.go#L88) | Used to define a function to skip this middleware when returned true | -| ErrorHandler | [output log and response 401](https://github.com/hertz-contrib/paseto/blob/main/option.go#L89) | Used to define a function which is executed when an error occurs | -| SuccessHandler | [save the claims to app.RequestContext](https://github.com/hertz-contrib/paseto/blob/main/option.go#L94) | Used to define a function which is executed when the token is valid | +| Option | Default | Description | +| -------------- | -------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | +| Next | [nil](https://github.com/hertz-contrib/paseto/blob/main/option.go#L88) | Used to define a function to skip this middleware when returned true | +| ErrorHandler | [output log and response 401](https://github.com/hertz-contrib/paseto/blob/main/option.go#L89) | Used to define a function which is executed when an error occurs | +| SuccessHandler | [save the claims to app.RequestContext](https://github.com/hertz-contrib/paseto/blob/main/option.go#L94) | Used to define a function which is executed when the token is valid | | KeyLookup | [header:Authorization](https://github.com/hertz-contrib/paseto/blob/main/option.go#L97) | Used to define a string in the form of ":" that is used to create an Extractor that extracts the token from the request | -| TokenPrefix | "" | Used to define a string that holds the prefix for the token lookup | -| ParseFunc | [parse V4 Public Token](https://github.com/hertz-contrib/paseto/blob/main/option.go#L98) | Used to parse and verify token | +| TokenPrefix | "" | Used to define a string that holds the prefix for the token lookup | +| ParseFunc | [parse V4 Public Token](https://github.com/hertz-contrib/paseto/blob/main/option.go#L98) | Used to parse and verify token | ### Next @@ -234,12 +234,12 @@ func performRequest() { func main() { h := server.New(server.WithHostPorts(":8080")) - + handler := func(ctx context.Context, c *app.RequestContext) { c.JSON(http.StatusUnauthorized, "invalid token") c.Abort() } - + h.GET("/paseto/withsecret", func(c context.Context, ctx *app.RequestContext) { now := time.Now() genTokenFunc := paseto.DefaultGenTokenFunc() @@ -622,11 +622,11 @@ func main() { ## Version comparison -| Version | Local | Public | -| ------- | ------------------------------------------------------------ | ------------------------------- | -| v1 | Encrypted with `AES-256-CBC` and signed with HMAC-SHA-256 | Signed with `RSA-SHA-256` | -| v2 | Encrypted with `XSalsa20Poly1305` and signed with `HMAC-SHA-384` | Signed with `EdDSA`(`Ed25519`) | -| v3 | Encrypted with `XChaCha20Poly1305` and signed with`HMAC-SHA-384` | Signed with `EdDSA`(`Ed25519`) | +| Version | Local | Public | +| ------- | --------------------------------------------------------------------- | ------------------------------ | +| v1 | Encrypted with `AES-256-CBC` and signed with HMAC-SHA-256 | Signed with `RSA-SHA-256` | +| v2 | Encrypted with `XSalsa20Poly1305` and signed with `HMAC-SHA-384` | Signed with `EdDSA`(`Ed25519`) | +| v3 | Encrypted with `XChaCha20Poly1305` and signed with`HMAC-SHA-384` | Signed with `EdDSA`(`Ed25519`) | | v4 | Encrypted with `XChaCha20Poly1305` and signed with `HMAC-SHA-512-256` | Signed with `EdDSA`(`Ed448`) | ## Full Example diff --git a/content/en/docs/hertz/tutorials/basic-feature/middleware/pprof.md b/content/en/docs/hertz/tutorials/basic-feature/middleware/pprof.md index 551e70a93d..22d13d9a12 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/middleware/pprof.md +++ b/content/en/docs/hertz/tutorials/basic-feature/middleware/pprof.md @@ -4,10 +4,8 @@ date: 2022-09-24 weight: 7 keywords: ["pprof", "performance analysis"] description: "Hertz provides the pprof extension to help users perform performance analysis on Hertz projects. " - --- - Hertz provides the [pprof](https://github.com/hertz-contrib/pprof) extension to help users perform performance analysis on Hertz projects. The implementation of the [pprof](https://github.com/hertz-contrib/pprof) extension refers to the implementation of [Gin](https://github.com/gin-contrib/pprof). ## Install @@ -97,8 +95,8 @@ RouteRegister(rg *route.RouterGroup, prefixOptions ...string) The `pprof` prefix registered in this way is the result of splicing the prefix of the routing group and the custom prefix. -* If the user does not specify a prefix, the prefix of the registered `pprof` is the result of concatenating the prefix of the routing group and the default prefix `/debug/pprof`, that is, `/xxx/debug/pprof` (xxx is the prefix of the routing group); -* If the user specifies a prefix, the prefix of the registered `pprof` is the result of concatenating the prefix of the routing group and the custom prefix. For example, in the following example, the registered `pprof` prefix is `/admin/pprof`. +- If the user does not specify a prefix, the prefix of the registered `pprof` is the result of concatenating the prefix of the routing group and the default prefix `/debug/pprof`, that is, `/xxx/debug/pprof` (xxx is the prefix of the routing group); +- If the user specifies a prefix, the prefix of the registered `pprof` is the result of concatenating the prefix of the routing group and the custom prefix. For example, in the following example, the registered `pprof` prefix is `/admin/pprof`. Sample code: @@ -138,9 +136,9 @@ func main() { Access `localhost:8888/debug/pprof` via browser -* Hertz port number defaults to 8888 -* pprof default address prefix is `debug/pprof` -* The port number and access route are the same as the user's actual port number and `pprof` prefix +- Hertz port number defaults to 8888 +- pprof default address prefix is `debug/pprof` +- The port number and access route are the same as the user's actual port number and `pprof` prefix ### Via `go tool pprof` diff --git a/content/en/docs/hertz/tutorials/basic-feature/middleware/recovery.md b/content/en/docs/hertz/tutorials/basic-feature/middleware/recovery.md index 30273cf064..9a2c4fde81 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/middleware/recovery.md +++ b/content/en/docs/hertz/tutorials/basic-feature/middleware/recovery.md @@ -4,7 +4,6 @@ date: 2022-12-15 weight: 2 keywords: ["Recovery", "panic recovery"] description: "The Recovery middleware is preset by the Hertz framework to provide the feature of Panic recovery for the Hertz framework." - --- The Recovery middleware is preset by the Hertz framework. The `server.Default()` will register Recovery middleware by default to provide the feature of Panic recovery for the Hertz framework. @@ -16,7 +15,7 @@ h := server.New() h.Use(recovery.Recovery()) ``` -The Recovery middleware will recover any panics in the Hertz framework. When a panic occurs, the Recover middleware will print out the panic time, content and stack information by default, then set the status code as 500 through `*app.RequestContext'`. +The Recovery middleware will recover any panics in the Hertz framework. When a panic occurs, the Recover middleware will print out the panic time, content and stack information by default, then set the status code as 500 through `*app.RequestContext'`. ## Import diff --git a/content/en/docs/hertz/tutorials/basic-feature/middleware/requestid.md b/content/en/docs/hertz/tutorials/basic-feature/middleware/requestid.md index 6a89879c43..1908a33b83 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/middleware/requestid.md +++ b/content/en/docs/hertz/tutorials/basic-feature/middleware/requestid.md @@ -4,7 +4,6 @@ date: 2022-10-01 weight: 9 keywords: ["Request ID", "X-Request-ID"] description: "Hertz provides Request ID middleware that can operate on `X-Request-ID`." - --- `X-Request-ID` is a common non-standard response fields in HTTP Headers, used to correlate HTTP requests between a client and server. @@ -70,7 +69,7 @@ Hertz is able to add an identifier to the response using the `X-Request-ID` head The Request ID middleware provides the default configuration, you can also customize the following configuration using `WithGenerator`, `WithCustomHeaderStrKey`, `WithHandler` functions according to different scenarios. | configuration | Description | -|------------------------|--------------------------------------------------------------------------------------------| +| ---------------------- | ------------------------------------------------------------------------------------------ | | WithGenerator | Define a function that generates a Request ID. By default, a UUID identifier is generated. | | WithCustomHeaderStrKey | Define the key value of the Request ID. By default, the key value is `X-Request-ID`. | | WithHandler | Define the handler function of the Request ID. | diff --git a/content/en/docs/hertz/tutorials/basic-feature/middleware/secure.md b/content/en/docs/hertz/tutorials/basic-feature/middleware/secure.md index c4519456eb..82f827e827 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/middleware/secure.md +++ b/content/en/docs/hertz/tutorials/basic-feature/middleware/secure.md @@ -32,7 +32,7 @@ package main import ( "context" - + "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/hertz-contrib/secure" @@ -60,7 +60,7 @@ Most of the Secure configuration items are designed to simplify the user's confi Secure provides the `New()` function for integrating Secure into Hertz, which is configured by default as follows | Configuration | Description | Default Value | -|---------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------| +| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------- | | WithSSLRedirect | If `WithSSLRedirect` is set to true, only https requests will be allowed | true | | WithIsDevelopment | If `WithIsDevelopment` is set to true, the entire security policy of the middleware application will be completely disabled | false | | WithSTSSecond | `WithSTSSecond` is used to set the number of seconds for the max-age of Strict-Transport-Security | 315360000 | @@ -158,7 +158,7 @@ import ( "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/cloudwego/hertz/pkg/common/utils" - + "github.com/hertz-contrib/secure" ) diff --git a/content/en/docs/hertz/tutorials/basic-feature/middleware/sentry.md b/content/en/docs/hertz/tutorials/basic-feature/middleware/sentry.md index 3b47f2e458..f910431774 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/middleware/sentry.md +++ b/content/en/docs/hertz/tutorials/basic-feature/middleware/sentry.md @@ -4,7 +4,6 @@ date: 2022-11-25 weight: 11 keywords: ["Sentry", "real-time error monitoring"] description: "Hertz integrates with the Sentry-Go SDK by using the middleware hertzsentry. " - --- Sentry is an open-source real-time error monitoring project that supports many platforms, including web front-end, server-side, mobile, and game-side. Hertz integrates with the [Sentry-Go](https://docs.sentry.io/platforms/go/) SDK by using the middleware [hertzsentry](https://github.com/hertz-contrib/hertzsentry). It provides several unified interfaces to help users get access to the sentry hub and report error messages. @@ -27,7 +26,7 @@ package main import ( "context" "log" - + "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/getsentry/sentry-go" @@ -58,7 +57,7 @@ func main() { } // use sentry middleware and config with your requirements. - // attention! you should use sentry handler after recovery.Recovery() + // attention! you should use sentry handler after recovery.Recovery() h.Use(hertzsentry.NewSentry( hertzsentry.WithSendRequest(true), hertzsentry.WithRePanic(true), @@ -84,13 +83,13 @@ func main() { Hertz integrates the functionality of Sentry-Go through the use of middleware. The `hertzsentry.options` structure defines the configuration information for hertzsentry and provides a default configuration that can be customized by the user according to the business scenario. -| Parameter | Introduction | -| --------------- | ------------------------------------------------------------ | -| rePanic | Used to configure whether Sentry should panic again after recovery; set to true if the Recover middleware is used, the default is false. | +| Parameter | Introduction | +| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| rePanic | Used to configure whether Sentry should panic again after recovery; set to true if the Recover middleware is used, the default is false. | | waitForDelivery | Used to configure whether the request should be blocked and the buffer emptied before continuing to process the response (**only asynchronous transfers really have an operation to empty the buffer**). If using Recover middleware, it is safe to skip this option or set it to false, the default is false. | -| sendRequest | Used to configure whether the current request headers should be added when capturing sentry events, the default is false. | -| sendBody | Used to configure whether to add the current request body information when capturing sentry events, the default is false. | -| timeout | Used to configure the timeout for sentry event delivery requests, the default is 2 seconds. | +| sendRequest | Used to configure whether the current request headers should be added when capturing sentry events, the default is false. | +| sendBody | Used to configure whether to add the current request body information when capturing sentry events, the default is false. | +| timeout | Used to configure the timeout for sentry event delivery requests, the default is 2 seconds. | ### Flush(Go-Sentry) diff --git a/content/en/docs/hertz/tutorials/basic-feature/middleware/session.md b/content/en/docs/hertz/tutorials/basic-feature/middleware/session.md index 62e10de422..50b2b7c717 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/middleware/session.md +++ b/content/en/docs/hertz/tutorials/basic-feature/middleware/session.md @@ -4,7 +4,6 @@ date: 2022-10-07 weight: 6 keywords: ["Session"] description: "Hertz provides an implementation of Session." - --- Session is a special object created by the server to hold user's state. @@ -69,7 +68,7 @@ The introduction of the interface methods is as follows: **Note:** Session Wraps thinly [gorilla-session](https://github.com/gorilla/sessions) methods. | Method | Function Signatures | Description | -|----------|-----------------------------------------------|----------------------------------------------------------------------------------------| +| -------- | --------------------------------------------- | -------------------------------------------------------------------------------------- | | ID | `ID() string` | Used to fetch the Session ID generated by stores, it should not be used for user data. | | Get | `Get(key interface{}) interface{}` | Used to get the session value associated to the given key. | | Set | `Set(key, val interface{})` | Used to set the session value associated to the given key. | diff --git a/content/en/docs/hertz/tutorials/basic-feature/middleware/swagger.md b/content/en/docs/hertz/tutorials/basic-feature/middleware/swagger.md index dbb85c1845..2e405a9e02 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/middleware/swagger.md +++ b/content/en/docs/hertz/tutorials/basic-feature/middleware/swagger.md @@ -4,7 +4,6 @@ date: 2022-10-06 weight: 8 keywords: ["Swagger", "RESTful API"] description: "Hertz middleware to automatically generate RESTful API documentation with Swagger 2.0." - --- Hertz middleware to automatically generate RESTful API documentation with Swagger 2.0. @@ -30,8 +29,8 @@ go install github.com/swaggo/swag/cmd/swag@latest ``` 3. Run the [Swag][Swag] at your Go project root path(for instance `~/root/go-project-name`), -[Swag][Swag] will parse comments and generate required files(`docs` folder and `docs/doc.go`) -at `~/root/go-project-name/docs`. + [Swag][Swag] will parse comments and generate required files(`docs` folder and `docs/doc.go`) + at `~/root/go-project-name/docs`. ```sh swag init @@ -44,7 +43,7 @@ swag init --parseDependency --parseInternal --parseDepth 5 --instanceName "swagg ``` | Options | Default | Description | -| --------------- | --------- |----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| --------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | parseInternal | false | Parse go files in internal packages. | | parseDependency | false | Parse go files inside dependency folder. | | parseDepth | 100 | Dependency parse depth.If you know the depth of the data structure to be parsed, it is recommended to use `parseDepth`, the swag command execution time will be greatly reduced. | @@ -194,14 +193,15 @@ func main() { ``` -| Option | Type | Default | Description | -| ------------------------ | ------ | ---------- | ------------------------------------------------------------ | -| URL | string | "doc.json" | URL pointing to API definition | +| Option | Type | Default | Description | +| ------------------------ | ------ | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| URL | string | "doc.json" | URL pointing to API definition | | DocExpansion | string | "list" | Controls the default expansion setting for the operations and tags. It can be 'list' (expands only the tags), 'full' (expands the tags and operations) or 'none' (expands nothing). | -| DeepLinking | bool | true | If set to true, enables deep linking for tags and operations. See the Deep Linking documentation for more information. | -| DefaultModelsExpandDepth | int | 1 | Default expansion depth for models (set to -1 completely hide the models). | -| PersistAuthorization | bool | false | If set to true, it persists authorization data and it would not be lost on browser close/refresh. | -| Oauth2DefaultClientID | string | "" | If set, it's used to prepopulate the *client_id* field of the OAuth2 Authorization dialog. | +| DeepLinking | bool | true | If set to true, enables deep linking for tags and operations. See the Deep Linking documentation for more information. | +| DefaultModelsExpandDepth | int | 1 | Default expansion depth for models (set to -1 completely hide the models). | +| PersistAuthorization | bool | false | If set to true, it persists authorization data and it would not be lost on browser close/refresh. | +| Oauth2DefaultClientID | string | "" | If set, it's used to prepopulate the _client_id_ field of the OAuth2 Authorization dialog. | + --- [Swag]: https://github.com/swaggo/swag diff --git a/content/en/docs/hertz/tutorials/basic-feature/network-lib.md b/content/en/docs/hertz/tutorials/basic-feature/network-lib.md index e3f68a9276..5ddeb6255a 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/network-lib.md +++ b/content/en/docs/hertz/tutorials/basic-feature/network-lib.md @@ -4,14 +4,13 @@ date: 2022-06-20 weight: 3 keywords: ["netpoll", "go net"] description: "Hertz integrated Netpoll and Golang network lib by default. Users can choose the appropriate one according to the actual scenarios to meet the best performance." - --- ## Usage While creating a server, Hertz uses netpoll by default, but this behavior can be modified by configuration: ->Note: Netpoll currently does not support Windows. Windows will automatically switch the network library to go net through conditional compilation. +> Note: Netpoll currently does not support Windows. Windows will automatically switch the network library to go net through conditional compilation. ```go server.New(server.WithTransport(standard.NewTransporter)) @@ -29,8 +28,8 @@ client.NewClient(client.WithDialer(netpoll.NewDialer())) 1. If you need to start a TLS server, Please use `go net` lib instead. `netpoll` is now working on it but not ready yet. 2. Due to the different I/O trigger model between the two network libs, `go net` for ET model and `netpoll` for LT model, which makes the application scenarios of the two libs somewhat different. -Under the ET mode, Read / Write events will be handled by the framework. Under the LT mode, Read / Write events will be handled by the network lib itself instead. -So with the small size requests, better schedule strategy provided by netpoll will makes LT model perform better; But under the situation with large size requests, since the Read / Write is not controlled by the framework layer, it may cause memory pressure because large amount of data will be loaded into the memory but can not be handled in time. + Under the ET mode, Read / Write events will be handled by the framework. Under the LT mode, Read / Write events will be handled by the network lib itself instead. + So with the small size requests, better schedule strategy provided by netpoll will makes LT model perform better; But under the situation with large size requests, since the Read / Write is not controlled by the framework layer, it may cause memory pressure because large amount of data will be loaded into the memory but can not be handled in time. - Under the situation with large request size ( generally larger than 1M ), go net lib with streaming is recommended. - In other situation, netpoll lib is recommended for extreme performance. diff --git a/content/en/docs/hertz/tutorials/basic-feature/protocol/_index.md b/content/en/docs/hertz/tutorials/basic-feature/protocol/_index.md index 9275f2b6ad..cfcdf7eb89 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/protocol/_index.md +++ b/content/en/docs/hertz/tutorials/basic-feature/protocol/_index.md @@ -4,7 +4,6 @@ date: 2022-05-23 weight: 7 keywords: ["TLS", "ALPN", "Websocket", "HTTP2", "HTTP3", "SSE"] description: "Hertz supported protocols." - --- ## TLS @@ -24,7 +23,7 @@ Hertz implements support for WebSocket based on `hijack`. Hertz references [net/http2](https://github.com/golang/net/tree/master/http2) to implement support for HTTP2, while also supporting both h2 and h2c. -## HTTP3 +## HTTP3 Hertz reference [quic-go](https://github.com/quic-go/quic-go) to implement support for HTTP3. diff --git a/content/en/docs/hertz/tutorials/basic-feature/protocol/http2.md b/content/en/docs/hertz/tutorials/basic-feature/protocol/http2.md index 7a557f404d..350d88f4c3 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/protocol/http2.md +++ b/content/en/docs/hertz/tutorials/basic-feature/protocol/http2.md @@ -1,11 +1,9 @@ --- title: "HTTP2" -date: 2022-12-15 +date: 2022-12-15 weight: 2 keywords: ["HTTP/2", "HTTP", "h2", "h2c"] description: "Hertz supports both h2 and h2c. It uses net/http2 implementation for reference." - - --- HTTP/2 is a replacement for how HTTP is expressed “on the wire.” It is not a ground-up rewrite of the protocol; HTTP methods, status codes and semantics are the same, and it should be possible to use the same APIs as HTTP/1.x (possibly with some small additions) to represent the protocol. @@ -189,7 +187,7 @@ func main() { ### Server | **Option** | **Default** | **Description** | -|:-------------------|:------------|--------------------------------------------------------------------------------------------------| +| :----------------- | :---------- | ------------------------------------------------------------------------------------------------ | | `ReadTimeout` | `0` | The timeout for reading available resources from the server after the connection is established, | | `DisableKeepAlive` | `false` | Whether to disable `Keep-Alive` mode | @@ -314,19 +312,19 @@ func WithDisableKeepAlive(disableKeepAlive bool) Option ### Client | **Option** | **Default** | **Description** | -|------------------------------|-----------------------------------------|----------------------------------------------------------------------------------------------------------------------| +| ---------------------------- | --------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | | `MaxHeaderListSize` | `0`, means use the default limit (10MB) | Refers to `SETTINGS_MAX_HEADER_LIST_SIZE` in the HTTP2 specification. | | `AllowHTTP` | `false` | Set whether to allow HTTP,the h2c switch | | `ReadIdleTimeout` | `0`,which means no health check | If the connection does not receive any frames during this interval, a health check is performed using `ping` frames. | -| `PingTimeout` | `15s` | A timeout period after which the connection will be closed if no response to `Ping` is received. | +| `PingTimeout` | `15s` | A timeout period after which the connection will be closed if no response to `Ping` is received. | | `WriteByteTimeout` | `0` | If no data is written during this time interval, the connection will be closed. | -| `StrictMaxConcurrentStreams` | `false` | Controls whether the server's `SETTINGS_MAX_CONCURRENT_STREAMS`should be respected globally. | +| `StrictMaxConcurrentStreams` | `false` | Controls whether the server's `SETTINGS_MAX_CONCURRENT_STREAMS`should be respected globally. | | `DialTimeout` | `1s` | imeout for establishing new connections to hosts. | | `MaxIdleConnDuration` | `0` | Idle keep-alive connections are closed after this duration. | | `DisableKeepAlive` | `false` | Connection will close after each request when set this to true. | | `Dialer` | `netpoll.NewDialer()` | Default Dialer is used if not set. | | `TLSConfig` | `nil` | Whether to use TLS (aka SSL or HTTPS) for host connections. | -| `RetryConfig` | `nil` | All configurations related to retry | +| `RetryConfig` | `nil` | All configurations related to retry | Sample: @@ -501,7 +499,7 @@ Set the timeout for `Ping` responses, after which the connection will be closed Function Signature: ```go -func WithPingTimeout(pt time.Duration) ClientOption +func WithPingTimeout(pt time.Duration) ClientOption ``` #### WithAllowHTTP @@ -511,7 +509,7 @@ Used to set whether to allow HTTP. if enabled, the client will use h2c mode. Not Function Signature: ```go -func WithAllowHTTP(allow bool) ClientOption +func WithAllowHTTP(allow bool) ClientOption ``` #### WithDialer diff --git a/content/en/docs/hertz/tutorials/basic-feature/protocol/http3.md b/content/en/docs/hertz/tutorials/basic-feature/protocol/http3.md index b4b1d36128..ded38f9a6e 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/protocol/http3.md +++ b/content/en/docs/hertz/tutorials/basic-feature/protocol/http3.md @@ -4,7 +4,6 @@ date: 2023-07-29 weight: 3 keywords: ["QUIC", "HTTP", "HTTP3"] description: "Hertz-HTTP3 implementation based quic-go." - --- QUIC protocol is a transport layer network protocol that provides security equivalent to TLS/SSL, while also having lower connection and transmission latency. `QUIC` is currently mainly used in the `HTTP` protocol, which is known as `HTTP/3` and is the third official version of the `HTTP` protocol. @@ -19,7 +18,7 @@ For the interface design scheme provided by Hertz to support Hertz HTTP3 in the go get github.com/hertz-contrib/http3 ``` ->Note: The go version must be greater than or equal to 1.19. +> Note: The go version must be greater than or equal to 1.19. ## Network Layer and Protocol Layer Registration @@ -40,19 +39,19 @@ h.AddProtocol(suite.HTTP3, factory.NewServerFactory(&http3.Option{})) ### Server -| **Option** | **Description** | -| :----------------- | -------------------------------------------- | -| WithTransport | Set the network layer implementation | -| WithAltTransport | Set the alternative network layer implementation. The AltTransporter will be used for parallel listening - both in `TCP` and `QUIC` | -| WithALPN | Set whether to enable `ALPN` | -| WithTLS | Set `TLS` Config | -| WithHostPorts | Set the host and port for starting the service | +| **Option** | **Description** | +| :--------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| WithTransport | Set the network layer implementation | +| WithAltTransport | Set the alternative network layer implementation. The AltTransporter will be used for parallel listening - both in `TCP` and `QUIC` | +| WithALPN | Set whether to enable `ALPN` | +| WithTLS | Set `TLS` Config | +| WithHostPorts | Set the host and port for starting the service | ## Sample Code ### Server ->Note: The `QUIC` protocol relies on the `TLS` protocol, so `TLS` configuration needs to be provided. +> Note: The `QUIC` protocol relies on the `TLS` protocol, so `TLS` configuration needs to be provided. ```go package main diff --git a/content/en/docs/hertz/tutorials/basic-feature/protocol/sse.md b/content/en/docs/hertz/tutorials/basic-feature/protocol/sse.md index c622b08719..b61e74b1b2 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/protocol/sse.md +++ b/content/en/docs/hertz/tutorials/basic-feature/protocol/sse.md @@ -4,7 +4,6 @@ date: 2023-05-12 weight: 6 keywords: ["SSE", "HTTP", "Server-Sent Events"] description: "Hertz supports SSE, allowing the server to send events to the client through simple HTTP response." - --- SSE is short for Server-Sent Events, which is a server push technology that allows the server to send events to clients through simple HTTP responses. @@ -30,9 +29,9 @@ import ( "context" "net/http" "time" - + "github.com/hertz-contrib/sse" - + "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/cloudwego/hertz/pkg/common/hlog" @@ -40,16 +39,16 @@ import ( func main() { h := server.Default() - + h.GET("/sse", func(ctx context.Context, c *app.RequestContext) { lastEventID := sse.GetLastEventID(c) - + // The client can inform the server of the last event received through Last-Event-ID. hlog.CtxInfof(ctx, "last event ID: %s", lastEventID) - + // You must set status code and response headers before calling Render for first time. c.SetStatusCode(http.StatusOK) - + s := sse.NewStream(c) for t := range time.NewTicker(1 * time.Second).C { event := &sse.Event{ @@ -62,7 +61,7 @@ func main() { } } }) - + h.Spin() } ``` @@ -182,14 +181,14 @@ package main func main() { h := server.Default() - + h.GET("/sse", func(ctx context.Context, c *app.RequestContext) { c.SetStatusCode(http.StatusOK) c.Response.Header.Set("X-Accel-Buffering", "no") s := sse.NewStream(c) // ... }) - + } ``` @@ -201,22 +200,22 @@ Publish is used to send an event message to the client. The format of the event type Event struct { // Name of this event. Event string - + // Data associated with this event. Data []byte - + // ID number assigned by Server Sent Events protocol. ID string - + // Retry duration time specified in milliseconds; if present then browser will attempt reconnect after that many milliseconds have elapsed since last message received from server. - Retry time.Duration + Retry time.Duration } ``` Function signature: ```go -func (c *Stream) Publish(event *Event) error +func (c *Stream) Publish(event *Event) error ``` ### GetLastEventID diff --git a/content/en/docs/hertz/tutorials/basic-feature/protocol/tls.md b/content/en/docs/hertz/tutorials/basic-feature/protocol/tls.md index 1e7943da22..7fa9814276 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/protocol/tls.md +++ b/content/en/docs/hertz/tutorials/basic-feature/protocol/tls.md @@ -4,7 +4,6 @@ date: 2022-11-06 weight: 5 keywords: ["TLS", "HTTP"] description: "Hertz supports TLS secure transmission, helping users achieve data confidentiality and integrity." - --- Hertz supports TLS secure transmission, helping users achieve data confidentiality and integrity. @@ -14,7 +13,7 @@ Hertz supports TLS secure transmission, helping users achieve data confidentiali In `tls.Config`, the parameters that the server and client both can use are as follows: | Parameter | Introduce | -|:---------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------| +| :-------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------- | | Certificates | Used to add certificates, multiple certificates can be configured.
Both ends automatically select the first certificate for verification. | | VerifyPeerCertificate | Used to verify the peer certificate.
Called after certificate verification on either side. | | VerifyConnection | After both certificates are verified, TLS connection verification is performed. | @@ -43,7 +42,7 @@ func WithTLS(cfg *tls.Config) config.Option { In `tls.Config`, in addition to the above basic parameters, the parameters that can be configured by the server are as follows: | Parameter | Introduce | -|:--------------------:|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| :------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | GetCertificate | Returns a certificate based on client SNI information or when the certificate set is empty. | | GetClientCertificate | It is used to return the client certificate when the server requires to verify the client certificate. | | GetConfigForClient | When the server receives ClientHello from the client, it returns the configuration information.
If non-empty configuration information is returned, it will be used for this TLS connection. | @@ -139,7 +138,7 @@ For a complete usage example, see [example](https://github.com/cloudwego/hertz-e In `tls.Config`, in addition to the above basic parameters, the parameters that can be configured by the client are as follows: | Parameter | Introduce | -|:------------------:|:--------------------------------------------------------------------------------| +| :----------------: | :------------------------------------------------------------------------------ | | ServerName | Validate the hostname against the returned certificate information. | | InsecureSkipVerify | It is used for whether the client enables server-side certificate verification. | | RootCAs | The certificate used by the client to authenticate the server. | @@ -207,8 +206,7 @@ func main() { } ``` -> Note:Currently, Hertz TLS server is not supported Netpoll network library temporarily.
-> `c, err := client.NewClient(client.WithTLSConfig(cfg), client.WithDialer(netpoll.NewDialer())` support is still on the way. +> Note:Currently, Hertz TLS server is not supported Netpoll network library temporarily.
> `c, err := client.NewClient(client.WithTLSConfig(cfg), client.WithDialer(netpoll.NewDialer())` support is still on the way. For a complete usage example, see [example](https://github.com/cloudwego/hertz-examples/tree/main/protocol/tls) . @@ -379,8 +377,8 @@ func main() { InsecureSkipVerify: true, } c, err := client.NewClient( - client.WithTLSConfig(clientCfg), - client.WithDialer(standard.NewDialer()), + client.WithTLSConfig(clientCfg), + client.WithDialer(standard.NewDialer()), ) } ``` diff --git a/content/en/docs/hertz/tutorials/basic-feature/protocol/websocket.md b/content/en/docs/hertz/tutorials/basic-feature/protocol/websocket.md index 3283993307..c0d72afe7f 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/protocol/websocket.md +++ b/content/en/docs/hertz/tutorials/basic-feature/protocol/websocket.md @@ -1,11 +1,11 @@ --- title: "Websocket" -date: 2022-09-13 +date: 2022-09-13 weight: 4 keywords: ["WebSocket", "HTTP", "hijack", "TCP"] description: "Hertz implements support for WebSocket based on hijack." - --- + WebSocket is a type of full-duplex communication that can be performed on a single TCP connection and is located at the application layer of the OSI model. WebSocket makes data exchange between client and server easier, allowing the server to actively push data to the client. In the WebSocket API, the browser and the server only need to complete a handshake that a persistent connection can be created between the two, and two-way data transmission can be performed. @@ -94,15 +94,15 @@ The following is the optional configuration parameters for using Hertz WebSocket This section is organized around the `websocket.HertzUpgrader` structure. -| Parameter | Introduction | -| ------------------- | ------------------------------------------------------------ | -| `ReadBufferSize` | Used to set the size of the read buffer in bytes. If the buffer size is zero, then the size allocated by the HTTP server is used. The read buffer size does not limit the size of the messages that can be received. | -| `WriteBufferSize` | Used to set the size of the write buffer in bytes. If the buffer size is zero, then the size allocated by the HTTP server is used. The write buffer size does not limit the size of the messages that can be sent. | -| `WriteBufferPool` | Used to set the buffer pool for write operations. | +| Parameter | Introduction | +| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `ReadBufferSize` | Used to set the size of the read buffer in bytes. If the buffer size is zero, then the size allocated by the HTTP server is used. The read buffer size does not limit the size of the messages that can be received. | +| `WriteBufferSize` | Used to set the size of the write buffer in bytes. If the buffer size is zero, then the size allocated by the HTTP server is used. The write buffer size does not limit the size of the messages that can be sent. | +| `WriteBufferPool` | Used to set the buffer pool for write operations. | | `Subprotocols` | Used to set the protocols supported by the server in order of preference. If this field is not nil, then the Upgrade method negotiates a sub-protocol by selecting the first match in this list to the protocol requested by the client. If there is no match, then no protocol is negotiated (the Sec-Websocket-Protocol header is not included in the handshake response). | -| `Error` | Used to set a function the generation of HTTP error responses. | -| `CheckOrigin` | Used to set a check function for Origin header for the request. If the Origin header of the request is acceptable, CheckOrigin returns true. | -| `EnableCompression` | Used to set whether the server should attempt to negotiate compression for each message (RFC 7692). Setting this value to true does not guarantee that compression will be supported. | +| `Error` | Used to set a function the generation of HTTP error responses. | +| `CheckOrigin` | Used to set a check function for Origin header for the request. If the Origin header of the request is acceptable, CheckOrigin returns true. | +| `EnableCompression` | Used to set whether the server should attempt to negotiate compression for each message (RFC 7692). Setting this value to true does not guarantee that compression will be supported. | ### WriteBufferPool diff --git a/content/en/docs/hertz/tutorials/basic-feature/proxy.md b/content/en/docs/hertz/tutorials/basic-feature/proxy.md index 2e95ca19e4..0e2ab66444 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/proxy.md +++ b/content/en/docs/hertz/tutorials/basic-feature/proxy.md @@ -4,7 +4,6 @@ date: 2022-09-08 weight: 12 keywords: ["Forward proxy", "Reverse proxy"] description: "Hertz provides forward and reverse proxy capabilities." - --- ## Forward proxy @@ -133,14 +132,14 @@ func NewSingleHostReverseProxy(target string, opts ...config.Option) (*reversePr ``` > - For `NewSingleHostReverseProxy` function, if no `config.ClientOption` is passed it will use the default global `client.Client` instance. -When passing `config.ClientOption` it will initialize a local `client.Client` instance. -Using `ReverseProxy.SetClient` if there is need for shared customized `client.Client` instance. +> When passing `config.ClientOption` it will initialize a local `client.Client` instance. +> Using `ReverseProxy.SetClient` if there is need for shared customized `client.Client` instance. > - The reverse proxy resets the header of the response, any such modifications before the request is made will be discarded. We provide the `SetXxx()` method for setting private properties | Method | Description | -|---------------------|-------------------------------------------| +| ------------------- | ----------------------------------------- | | `SetDirector` | use to customize protocol.Request | | `SetClient` | use to customize client | | `SetModifyResponse` | use to customize modify response function | @@ -153,7 +152,7 @@ package main import ( "context" - + "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/cloudwego/hertz/pkg/common/utils" @@ -172,7 +171,7 @@ func main() { "msg": "proxy success!!", }) }) - + h.GET("/backend", proxy.ServeHTTP) h.Spin() } @@ -241,7 +240,7 @@ func main() { #### Configuration | Configuration | Default | Description | -|----------------|---------------------------|------------------------------| +| -------------- | ------------------------- | ---------------------------- | | `WithDirector` | `nil` | customize the forward header | | `WithDialer` | `gorillaws.DefaultDialer` | for dialer customization | | `WithUpgrader` | `hzws.HertzUpgrader` | for upgrader customization | @@ -249,7 +248,7 @@ func main() { ### More Examples | Purpose | Sample Code | -|-------------------------|-------------------------------------------------------------------------------------------| +| ----------------------- | ----------------------------------------------------------------------------------------- | | Proxy tls | [code](https://github.com/cloudwego/hertz-examples/tree/main/reverseproxy/tls) | | Using service discovery | [code](https://github.com/cloudwego/hertz-examples/tree/main/reverseproxy/discovery) | | Use with middleware | [code](https://github.com/cloudwego/hertz-examples/tree/main/reverseproxy/use_middleware) | diff --git a/content/en/docs/hertz/tutorials/basic-feature/render.md b/content/en/docs/hertz/tutorials/basic-feature/render.md index 01271bdf4f..7fcffcd689 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/render.md +++ b/content/en/docs/hertz/tutorials/basic-feature/render.md @@ -1,10 +1,20 @@ --- -title: 'Render' +title: "Render" date: 2023-06-01 weight: 18 -keywords: ["Render", "JSON", "Data", "HTML", "Protobuf", "Text", "XML", "Customizing Rendering"] +keywords: + [ + "Render", + "JSON", + "Data", + "HTML", + "Protobuf", + "Text", + "XML", + "Customizing Rendering", + ] description: "The rendering capabilities provided by Hertz." ---- +--- Hertz supports rendering of JSON, HTML, Protobuf, etc. @@ -93,16 +103,16 @@ func main() { msg.Company = "company" msg.Location = "location" msg.Number = 123 - + c.IndentedJSON(consts.StatusOK, msg) - /* + /* will output : { "Company": "company", "Location": "location", "Number": 123 - } + } */ - + h.Spin() } ``` @@ -291,7 +301,7 @@ func main() { h.GET("someText", func(ctx context.Context, c *app.RequestContext) { c.String(consts.StatusOK, "message", "hello,world") }) - + h.Spin() } ``` diff --git a/content/en/docs/hertz/tutorials/basic-feature/retry.md b/content/en/docs/hertz/tutorials/basic-feature/retry.md index 41893e1df7..7d05e9cdd5 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/retry.md +++ b/content/en/docs/hertz/tutorials/basic-feature/retry.md @@ -4,7 +4,6 @@ date: 2022-10-01 weight: 13 keywords: ["Retry", "Client"] description: "Hertz provides custom retry logic for users." - --- Hertz provides users with customized retry logic, Let's take a look at how to use Client Retry. **Note: Hertz version >= v0.4.0** @@ -30,17 +29,17 @@ func main() { } ``` -| Configuration Name | Type | Description | -| :------------------ | :----------------------------------------------------------- | :----------------------------------------------------------- | -| WithMaxAttemptTimes | uint | Set the maximum attempts times. Default:1 times (That is, only request once without retry) | -| WithInitDelay | time.Duration | Set initial delay time. Default: 1ms | -| WithMaxDelay | time.Duration | Set the maximum delay time. Default: 100ms | -| WithMaxJitter | time.Duration | Set the maximum jitter time, which needs to be used in conjunction with `RandomDelayPolicy`, and will generate a random time not exceeding the maximum jitter time. Default: 20ms | -| WithDelayPolicy | type DelayPolicyFunc func(attempts uint, err error, retryConfig *Config) time.Duration | Set the delay policy, you can use any combination of the following four policies, `FixedDelayPolicy`, `BackOffDelayPolicy`, `RandomDelayPolicy`, `DefaultDelayPolicy` ( [See the next section **Delay Policy** for details](#delay-policy) ) . Default: DefaultDelayPolicy (That is, the retry delay is 0) | +| Configuration Name | Type | Description | +| :------------------ | :-------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| WithMaxAttemptTimes | uint | Set the maximum attempts times. Default:1 times (That is, only request once without retry) | +| WithInitDelay | time.Duration | Set initial delay time. Default: 1ms | +| WithMaxDelay | time.Duration | Set the maximum delay time. Default: 100ms | +| WithMaxJitter | time.Duration | Set the maximum jitter time, which needs to be used in conjunction with `RandomDelayPolicy`, and will generate a random time not exceeding the maximum jitter time. Default: 20ms | +| WithDelayPolicy | type DelayPolicyFunc func(attempts uint, err error, retryConfig \*Config) time.Duration | Set the delay policy, you can use any combination of the following four policies, `FixedDelayPolicy`, `BackOffDelayPolicy`, `RandomDelayPolicy`, `DefaultDelayPolicy` ( [See the next section **Delay Policy** for details](#delay-policy) ) . Default: DefaultDelayPolicy (That is, the retry delay is 0) | ### Delay Policy -`retry.WithDelayPolicy()` usage +`retry.WithDelayPolicy()` usage ```go cli, err := client.NewClient( @@ -52,13 +51,13 @@ cli, err := client.NewClient( ) ``` -| Function Name | Description | -| :----------------- | :----------------------------------------------------------- | +| Function Name | Description | +| :----------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | CombineDelay | It is used to combine any of the following four policies and sum the values calculated by the selected policy. When you only need one of the following four policies, you can choose to use `CombineDelay` or directly pass any policy into `WithDelayPolicy` as a parameter | -| FixedDelayPolicy | Set the fixed delay time and use the value set by `WithInitDelay` to generate an equivalent delay time | -| BackOffDelayPolicy | Set the exponential delay time. Use the value set by `WithInitDelay`. The exponential delay time is generated according to the number of retries currently | -| RandomDelayPolicy | Set the random delay time. Use the value set by `WithMaxJitte`r to generate a random delay time that does not exceed this value | -| DefaultDelayPolicy | Set the default delay time (That is, 0) . Generally, it is used alone and has no effect when combined with other policies | +| FixedDelayPolicy | Set the fixed delay time and use the value set by `WithInitDelay` to generate an equivalent delay time | +| BackOffDelayPolicy | Set the exponential delay time. Use the value set by `WithInitDelay`. The exponential delay time is generated according to the number of retries currently | +| RandomDelayPolicy | Set the random delay time. Use the value set by `WithMaxJitte`r to generate a random delay time that does not exceed this value | +| DefaultDelayPolicy | Set the default delay time (That is, 0) . Generally, it is used alone and has no effect when combined with other policies | ### Complete example @@ -94,7 +93,7 @@ func main() { ## Retry condition configuration -If you want to customize the conditions under which retries occur, you can use ` client SetRetryIfFunc() ` configuration. The parameter of this function is a function, and the signature is: +If you want to customize the conditions under which retries occur, you can use `client SetRetryIfFunc()` configuration. The parameter of this function is a function, and the signature is: ```go func(req *protocol.Request, resp *protocol.Response, err error) bool @@ -108,7 +107,7 @@ cli.SetRetryIfFunc(func(req *protocol.Request, resp *protocol.Response, err erro }) ``` -Note that if you do not set `client SetRetryIfFunc()` . We will judge according to Hertz's default retry conditions, that is, whether the request meets the following `DefaultRetryIf()` function and whether the call is idempotent. ( Idempotent call: when `canIdempotentRetry` is [true](#table1) in [pkg/protocol/http1/client.go::Do()](https://github.com/cloudwego/hertz/blob/develop/pkg/protocol/http1/client.go#L328 ) and [pkg/protocol/http1/client.go::doNonNilReqResp()](https://github.com/cloudwego/hertz/blob/develop/pkg/protocol/http1/client.go#L411) ) +Note that if you do not set `client SetRetryIfFunc()` . We will judge according to Hertz's default retry conditions, that is, whether the request meets the following `DefaultRetryIf()` function and whether the call is idempotent. ( Idempotent call: when `canIdempotentRetry` is [true](#table1) in [pkg/protocol/http1/client.go::Do()](https://github.com/cloudwego/hertz/blob/develop/pkg/protocol/http1/client.go#L328) and [pkg/protocol/http1/client.go::doNonNilReqResp()](https://github.com/cloudwego/hertz/blob/develop/pkg/protocol/http1/client.go#L411) ) ```Go // DefaultRetryIf Default retry condition, mainly used for idempotent requests. @@ -145,13 +144,13 @@ func isIdempotent(req *protocol.Request, resp *protocol.Response, err error) boo } ``` -Table - 1 When `canIdempotentRetry` in Hertz source code [doNonNilReqResp()](https://github.com/cloudwego/hertz/blob/develop/pkg/protocol/http1/client.go#L411) is true. +Table - 1 When `canIdempotentRetry` in Hertz source code [doNonNilReqResp()](https://github.com/cloudwego/hertz/blob/develop/pkg/protocol/http1/client.go#L411) is true. -| doNonNilReqResp() return true | -| ------------------------------------------------------------ | -| err = conn.SetWriteDeadline(currentTime.Add(c.WriteTimeout)) | -| err = reqI.Write(req, zw) | -| err = reqI.ProxyWrite(req, zw) | -| err = zw.Flush() | -| err = conn.SetReadTimeout(c.ReadTimeout) | +| doNonNilReqResp() return true | +| ----------------------------------------------------------------------------------------------------------- | +| err = conn.SetWriteDeadline(currentTime.Add(c.WriteTimeout)) | +| err = reqI.Write(req, zw) | +| err = reqI.ProxyWrite(req, zw) | +| err = zw.Flush() | +| err = conn.SetReadTimeout(c.ReadTimeout) | | ( err = respI.ReadHeaderAndLimitBody() \|\| err = respI.ReadBodyStream() ) && (err != errs.ErrBodyTooLarge) | diff --git a/content/en/docs/hertz/tutorials/basic-feature/route.md b/content/en/docs/hertz/tutorials/basic-feature/route.md index eb7985cf59..be615577b0 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/route.md +++ b/content/en/docs/hertz/tutorials/basic-feature/route.md @@ -2,27 +2,35 @@ title: "Route" date: 2022-09-06 weight: 2 -keywords: ["Route", "Route Group", "Static Route", "Parametric Route", "Routing Priority", "NoRoute", "NoMethod"] +keywords: + [ + "Route", + "Route Group", + "Static Route", + "Parametric Route", + "Routing Priority", + "NoRoute", + "NoMethod", + ] description: "The routing function provided by Hertz." - --- ## Route Registration Hertz provides methods like `GET`, `POST`, `PUT`, `DELETE`, `ANY` for registering routes. -| Method | Introduce | -| ------------ |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `Hertz.GET` | The method used to register the HTTP Method as GET | -| `Hertz.POST` | The method used to register the HTTP Method as POST | -| `Hertz.DELETE` | The method used to register the HTTP Method as DELETE | -| `Hertz.PUT` | The method used to register the HTTP Method as PUT | -| `Hertz.PATCH` | The method used to register the HTTP Method as PATCH | -| `Hertz.HEAD` | The method used to register the HTTP Method as HEAD | -| `Hertz.OPTIONS` | The method used to register the HTTP Method as OPTIONS | -| `Hertz.Handle` | The method supports to register a HTTP Method flexibly, which is the same as the above method when used to register a normal HTTP Method, and it also supports the registration of custom HTTP Method | -| `Hertz.Any` | The method for registering all HTTP Methods | -| `Hertz.StaticFile/Static/StaticFS` | For registering static files | +| Method | Introduce | +| ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Hertz.GET` | The method used to register the HTTP Method as GET | +| `Hertz.POST` | The method used to register the HTTP Method as POST | +| `Hertz.DELETE` | The method used to register the HTTP Method as DELETE | +| `Hertz.PUT` | The method used to register the HTTP Method as PUT | +| `Hertz.PATCH` | The method used to register the HTTP Method as PATCH | +| `Hertz.HEAD` | The method used to register the HTTP Method as HEAD | +| `Hertz.OPTIONS` | The method used to register the HTTP Method as OPTIONS | +| `Hertz.Handle` | The method supports to register a HTTP Method flexibly, which is the same as the above method when used to register a normal HTTP Method, and it also supports the registration of custom HTTP Method | +| `Hertz.Any` | The method for registering all HTTP Methods | +| `Hertz.StaticFile/Static/StaticFS` | For registering static files | Sample Code: @@ -38,7 +46,7 @@ import ( func main(){ h := server.Default(server.WithHostPorts("127.0.0.1:8080")) - + h.StaticFS("/", &app.FS{Root: "./", GenerateIndexPages: true}) h.GET("/get", func(ctx context.Context, c *app.RequestContext) { @@ -183,12 +191,12 @@ Hertz supports the use of named parameters such as `:name` to set routes, and na If we set the route `/user/:name`, the match is as follows -| path | | -| ---- | ---- | -| /user/gordon | matched | -| /user/you | matched | -| /user/gordon/profile | mismatched | -| /user/ | mismatched | +| path | | +| -------------------- | ---------- | +| /user/gordon | matched | +| /user/you | matched | +| /user/gordon/profile | mismatched | +| /user/ | mismatched | By using the `RequestContext.Param` method, we can get the parameters carried in the route. @@ -223,11 +231,11 @@ Hertz supports routing with wildcard parameters such as `*filepath`, and the wil If we set the route `/src/*filepath`, the match is as follows -| path | | -| ---- | ---- | -| /src/ | matched | -| /src/somefile.go | matched | -| /src/subdir/somefile.go | matched | +| path | | +| ----------------------- | ------- | +| /src/ | matched | +| /src/somefile.go | matched | +| /src/subdir/somefile.go | matched | By using the `RequestContext.Param` method, we can get the parameters carried in the route. @@ -377,7 +385,7 @@ The `307 Temporary Redirect` status code is triggered by any of the request meth You can cancel it in the configuration as follows: -````go +```go package main import "github.com/cloudwego/hertz/pkg/app/server" @@ -386,6 +394,6 @@ func main() { h := server.New(server.WithRedirectTrailingSlash(false)) ... } -```` +``` For more configuration-related information: [Configuration instruction](/docs/hertz/reference/config/) diff --git a/content/en/docs/hertz/tutorials/basic-feature/unit-test.md b/content/en/docs/hertz/tutorials/basic-feature/unit-test.md index a3bc50fa6a..1f3b111016 100644 --- a/content/en/docs/hertz/tutorials/basic-feature/unit-test.md +++ b/content/en/docs/hertz/tutorials/basic-feature/unit-test.md @@ -4,7 +4,6 @@ date: 2022-05-23 weight: 15 keywords: ["Unit Test"] description: "Hertz provides unit testing capabilities for users." - --- A good project can't be built without unit tests. To help users build good projects, hertz of course provides unit testing tools. @@ -146,15 +145,15 @@ type ResponseRecorder struct { The method provided by this object is as follows: -|Function Signature | Description | -|:--|:--| -|`func NewRecorder() *ResponseRecorder` |Return the initialized `ResponseRecorder` object | -|`func (rw *ResponseRecorder) Header() *protocol.ResponseHeader` |Return `ResponseRecorder.header` | -|`func (rw *ResponseRecorder) Write(buf []byte) (int, error)` |Write data of type `[]byte` to `ResponseRecorder.Body` | -|`func (rw *ResponseRecorder) WriteString(str string) (int, error)` |Write data of type `string` to `ResponseRecorder.Body` | -|`func (rw *ResponseRecorder) WriteHeader(code int)`|Set `ResponseRecorder.Code` and `ResponseRecorder.header.SetStatusCode(code)` | -|`func (rw *ResponseRecorder) Flush()` |Implemented `http.Flusher`, set `ResponseRecorder.Flushed` to true | -|`func (rw *ResponseRecorder) Result() *protocol.Response` | Return the response information generated by the handler, including at least StatusCode, Header, Body, and optional Trailer. In the future, it will support returning more response information | +| Function Signature | Description | +| :----------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `func NewRecorder() *ResponseRecorder` | Return the initialized `ResponseRecorder` object | +| `func (rw *ResponseRecorder) Header() *protocol.ResponseHeader` | Return `ResponseRecorder.header` | +| `func (rw *ResponseRecorder) Write(buf []byte) (int, error)` | Write data of type `[]byte` to `ResponseRecorder.Body` | +| `func (rw *ResponseRecorder) WriteString(str string) (int, error)` | Write data of type `string` to `ResponseRecorder.Body` | +| `func (rw *ResponseRecorder) WriteHeader(code int)` | Set `ResponseRecorder.Code` and `ResponseRecorder.header.SetStatusCode(code)` | +| `func (rw *ResponseRecorder) Flush()` | Implemented `http.Flusher`, set `ResponseRecorder.Flushed` to true | +| `func (rw *ResponseRecorder) Result() *protocol.Response` | Return the response information generated by the handler, including at least StatusCode, Header, Body, and optional Trailer. In the future, it will support returning more response information | ## Work with biz handler diff --git a/content/en/docs/hertz/tutorials/example/_index.md b/content/en/docs/hertz/tutorials/example/_index.md index 19b1bf768a..b87f89d418 100644 --- a/content/en/docs/hertz/tutorials/example/_index.md +++ b/content/en/docs/hertz/tutorials/example/_index.md @@ -4,7 +4,6 @@ linkTitle: "Example code" weight: 1 keywords: ["Hertz", "hertz-examples", "Bizdemo", "Server", "Client", "Hz"] description: "Hertz provides a series of code examples designed to help users get start with Hertz and be familiar with its features." - --- Hertz provides a series of code examples designed to help users get start with Hertz and be familiar with its features. Refer to [hertz-examples](https://github.com/cloudwego/hertz-examples) for more information. @@ -12,15 +11,19 @@ Hertz provides a series of code examples designed to help users get start with H ## Bizdemo ### hertz_gorm + - [hertz_gorm](https://github.com/cloudwego/hertz-examples/tree/main/bizdemo/hertz_gorm) :Example of using gorm in hertz server ### hertz_gorm_gen + - [hertz_gorm_gen](https://github.com/cloudwego/hertz-examples/tree/main/bizdemo/hertz_gorm_gen) :Example of using gorm/gen & proto IDL in hertz server ### hertz_jwt + - [hertz_jwt](https://github.com/cloudwego/hertz-examples/tree/main/bizdemo/hertz_jwt) :Example of using jwt in hertz server ### hertz_session + - [hertz_session](https://github.com/cloudwego/hertz-examples/tree/main/bizdemo/hertz_session) :Example of using distributed session and csrf in hertz server ### tiktok_demo @@ -34,12 +37,15 @@ Hertz provides a series of code examples designed to help users get start with H ## Server ### Run hertz + - [hello](https://github.com/cloudwego/hertz-examples/tree/main/hello) :Example of launching a hertz "hello world" application ### Config + - [config](https://github.com/cloudwego/hertz-examples/tree/main/config) :Example of configuring hertz server ### Protocol + - [HTTP1](https://github.com/cloudwego/hertz-examples/tree/main/protocol/http1) : Example of hertz using HTTP1 protocol - [TLS](https://github.com/cloudwego/hertz-examples/tree/main/protocol/tls) : Example of hertz using TLS protocol - [HTTP2](https://github.com/hertz-contrib/http2/tree/main/examples) : Example of hertz using HTTP2 protocol @@ -48,9 +54,11 @@ Hertz provides a series of code examples designed to help users get start with H - [SSE](https://github.com/hertz-contrib/sse/tree/main/examples) : Example of hertz using SSE protocol ### Route + - [Route](https://github.com/cloudwego/hertz-examples/tree/main/route) :Examples of registering routes, using route groups, and parameter routes ### Middleware + - [basic_auth](https://github.com/cloudwego/hertz-examples/tree/main/middleware/basicauth) :Example of using basic auth middleware - [CORS](https://github.com/cloudwego/hertz-examples/tree/main/middleware/CORS) :Example of using the CORS middleware - [custom](https://github.com/cloudwego/hertz-examples/tree/main/middleware/custom) :Example of custom middleware @@ -74,49 +82,64 @@ Hertz provides a series of code examples designed to help users get start with H - [Paseto](https://github.com/hertz-contrib/paseto/tree/main/example) :Example of using Paseto middleware ### Parameter binding and validation + - [binding](https://github.com/cloudwego/hertz-examples/tree/main/binding) :Example of parameter binding and validation ### Get Parameters + - [parameters](https://github.com/cloudwego/hertz-examples/tree/main/parameter) :Example of getting query, form, cookie, etc. parameters ### Documents + - [file](https://github.com/cloudwego/hertz-examples/tree/main/file) :Examples of file upload, file download, and static file services ### Render + - [render](https://github.com/cloudwego/hertz-examples/tree/main/render) :Example of render body as json, html, protobuf, etc ### Redirect + - [redirect](https://github.com/cloudwego/hertz-examples/tree/main/redirect) :Example of a redirect to an internal/external URI ### Streaming read/write + - [streaming](https://github.com/cloudwego/hertz-examples/tree/main/streaming) :Example of streaming read/write using hertz server ### Graceful shutdown + - [graceful_shutdown](https://github.com/cloudwego/hertz-examples/tree/main/graceful_shutdown) :Example of hertz server graceful shutdown ### Unit test + - [unit_test](https://github.com/cloudwego/hertz-examples/tree/main/unit_test) :Example of writing unit tests using the interface provided by hertz without network transmission ### Tracing + - [tracer](https://github.com/cloudwego/hertz-examples/tree/main/tracer) :Example of hertz using Jaeger for link tracing ### Monitoring + - [monitoring](https://github.com/cloudwego/hertz-examples/tree/main/monitoring) :hertz Example of metrics monitoring with Prometheus ### Multiple service + - [multiple_service](https://github.com/cloudwego/hertz-examples/tree/main/multiple_service) :Example of using hertz with multiple services ### Adaptor + - [adaptor](https://github.com/cloudwego/hertz-examples/tree/main/adaptor) :Example of using adaptor to integrate hertz with package built for `http.Handler` interface , including a demonstration on using [jade](https://github.com/Joker/jade) as template engine. ### Sentinel + - [sentinel](https://github.com/cloudwego/hertz-examples/tree/main/sentinel) :Example of using sentinel-golang in hertz ### Reverse proxy + - [reverseproxy](https://github.com/cloudwego/hertz-examples/tree/main/reverseproxy) :Example of using reverse proxy in hertz server ### Hlog + - [standard](https://github.com/cloudwego/hertz-examples/tree/main/hlog/standard) :Example of using Hertz's default implementation for logging - [custom](https://github.com/cloudwego/hertz-examples/tree/main/hlog/custom) :Example of log extension - [zap](https://github.com/cloudwego/hertz-examples/tree/main/hlog/zap) :Example of docking with zap and lumberjack in hertz server @@ -125,53 +148,69 @@ Hertz provides a series of code examples designed to help users get start with H - [slog](https://github.com/cloudwego/hertz-examples/tree/main/hlog/slog) :Example of docking with slog and lumberjack in hertz server ### Opentelemetry + - [opentelemetry](https://github.com/cloudwego/hertz-examples/tree/main/opentelemetry) :Example of using obs opentelemetry for docking with opentelemetry ### HTTP Trailer -- [trailer](https://github.com/cloudwego/hertz-examples/tree/main/trailer) :Example of using HTTP Trailer + +- [trailer](https://github.com/cloudwego/hertz-examples/tree/main/trailer) :Example of using HTTP Trailer ## Client ### Send request + - [send_request](https://github.com/cloudwego/hertz-examples/tree/main/client/send_request) :Example of sending an http request using the hertz client ### Client config + - [client_config](https://github.com/cloudwego/hertz-examples/tree/main/client/config) :Example of configuring the hertz client ### TLS + - [tls](https://github.com/cloudwego/hertz-examples/tree/main/protocol/tls) :Example of hertz client sending a tls request ### Add parameters + - [add_parameters](https://github.com/cloudwego/hertz-examples/tree/main/client/add_parameters) :Example of adding request parameters using the hertz client ### Upload file + - [upload_file](https://github.com/cloudwego/hertz-examples/tree/main/client/upload_file) :Example of uploading a file using the hertz client ### Middleware + - [middleware](https://github.com/cloudwego/hertz-examples/tree/main/client/middleware) :Example of using the hertz client middleware ### Streaming read + - [streaming_read](https://github.com/cloudwego/hertz-examples/tree/main/client/streaming_read) :Example of a streaming read response using the hertz client ### Forward proxy + - [forward_proxy](https://github.com/cloudwego/hertz-examples/tree/main/client/forward_proxy) :Example of configuring a forward proxy using the hertz client ### HTTP Trailer + - [trailer](https://github.com/cloudwego/hertz-examples/tree/main/trailer) :Example of using HTTP Trailer ## Hz ### Generate server code based on Thrift + - [thrift](https://github.com/cloudwego/hertz-examples/tree/main/hz/thrift) :Example of using hz with thrift to generate server code ### Generate server code based on Protobuf + - [protobuf](https://github.com/cloudwego/hertz-examples/tree/main/hz/protobuf) :Example of using hz with protobuf to generate server code ### Generate client code + - [hz_client](https://github.com/cloudwego/hertz-examples/tree/main/hz/hz_client) :Example of using hz to generate client code ### Custom templates + - [template](https://github.com/cloudwego/hertz-examples/tree/main/hz/template) :Example of using hz custom templates to generate server code ### Three-party plugins + - [plugin](https://github.com/cloudwego/hertz-examples/tree/main/hz/plugin) :Example of using hz to access third-party plugins diff --git a/content/en/docs/hertz/tutorials/framework-exten/_index.md b/content/en/docs/hertz/tutorials/framework-exten/_index.md index 071e592e60..29145f0166 100644 --- a/content/en/docs/hertz/tutorials/framework-exten/_index.md +++ b/content/en/docs/hertz/tutorials/framework-exten/_index.md @@ -3,7 +3,15 @@ title: "Framework Extension" linkTitle: "Framework Extension" weight: 5 date: 2022-06-22 -keywords: ["Framework Extension", "Logger Extension", "Monitoring Extension", "Service Registration and Service Discovery Extensions", "Network Library Extensions", "Protocol extension", "Response Writer Extension"] +keywords: + [ + "Framework Extension", + "Logger Extension", + "Monitoring Extension", + "Service Registration and Service Discovery Extensions", + "Network Library Extensions", + "Protocol extension", + "Response Writer Extension", + ] description: "Hertz provides users with framework extension capabilities." - --- diff --git a/content/en/docs/hertz/tutorials/framework-exten/log/_index.md b/content/en/docs/hertz/tutorials/framework-exten/log/_index.md index de9994bb90..7fdcf29cd6 100644 --- a/content/en/docs/hertz/tutorials/framework-exten/log/_index.md +++ b/content/en/docs/hertz/tutorials/framework-exten/log/_index.md @@ -5,7 +5,6 @@ weight: 1 date: 2022-06-22 keywords: ["Logger Extension"] description: "Hertz provides logger extension, and the interface is defined in `pkg/common/hlog`." - --- Hertz provides logger extension, and the interface is defined in `pkg/common/hlog`. @@ -25,7 +24,7 @@ type FullLogger interface { } ``` ->Note that the default logger makes use of the standard library `log.Logger` as its underlying output. So the filenames and line numbers shown in the log messages depend on the settings of call depth. Thus wrapping the implementation of hlog may cause inaccuracies for these two values. +> Note that the default logger makes use of the standard library `log.Logger` as its underlying output. So the filenames and line numbers shown in the log messages depend on the settings of call depth. Thus wrapping the implementation of hlog may cause inaccuracies for these two values. ## Inject your own logger diff --git a/content/en/docs/hertz/tutorials/framework-exten/log/logrus.md b/content/en/docs/hertz/tutorials/framework-exten/log/logrus.md index 59c8b7bde9..c20785cd3e 100644 --- a/content/en/docs/hertz/tutorials/framework-exten/log/logrus.md +++ b/content/en/docs/hertz/tutorials/framework-exten/log/logrus.md @@ -5,7 +5,6 @@ weight: 2 date: 2023-04-18 keywords: ["Logger Extension", "logrus"] description: "Hertz interfaces with logrus and lumberjack." - --- ## Logger structure @@ -22,7 +21,7 @@ type Logger struct { ## NewLogger `NewLogger` uses `defaultConfig()` to create and initialize a Logger. The required configuration can be passed into the function as a parameter. If no parameter is passed in, the initial configuration will be installed to create `Logger` -For related configuration, please refer to [option configuration](#option-configuration) below +For related configuration, please refer to [option configuration](#option-configuration) below Function Signature: @@ -80,7 +79,7 @@ func main() { Function Signature: ```go -func WithLogger(logger *logrus.Logger) Option +func WithLogger(logger *logrus.Logger) Option ``` Sample code: @@ -106,7 +105,7 @@ func main() { Function Signature: ```go -func WithHook(hook logrus.Hook) Option +func WithHook(hook logrus.Hook) Option ``` Sample code: @@ -174,7 +173,7 @@ func main() { return } } - + logger := hertzlogrus.NewLogger() // Provides compression and deletion lumberjackLogger := &lumberjack.Logger{ diff --git a/content/en/docs/hertz/tutorials/framework-exten/log/slog.md b/content/en/docs/hertz/tutorials/framework-exten/log/slog.md index b27c2c7ae6..3979881715 100644 --- a/content/en/docs/hertz/tutorials/framework-exten/log/slog.md +++ b/content/en/docs/hertz/tutorials/framework-exten/log/slog.md @@ -4,7 +4,6 @@ linkTitle: "slog" weight: 5 keywords: ["Logger Extension", "slog"] description: "Hertz interfaces with slog and lumberjack." - --- ## Logger structure @@ -107,7 +106,7 @@ func main() { `WithLevel` judges the incoming `*slog.LevelVar`. Only log levels higher than or equal to this will be recorded ->It is worth noting that if `WithLevel` is set together with `WithHandlerOptions`, the log level of WithLevel will override the log level in WithHandlerOptions +> It is worth noting that if `WithLevel` is set together with `WithHandlerOptions`, the log level of WithLevel will override the log level in WithHandlerOptions Function Signature: @@ -131,7 +130,7 @@ func main() { //Dynamically set the log level to Level Debug levelVar := slog.LevelVar{} levelVar.Set(slog.LevelDebug) - logger := hertzslog.NewLogger(hertzslog.WithLevel(&slog.LevelVar{})) + logger := hertzslog.NewLogger(hertzslog.WithLevel(&slog.LevelVar{})) } ``` @@ -143,7 +142,7 @@ func main() { Function Signature: ```go -func WithHandlerOptions(opts *slog.HandlerOptions) Option +func WithHandlerOptions(opts *slog.HandlerOptions) Option ``` Sample code: @@ -205,7 +204,7 @@ func main() { return } } - + logger := hertzslog.NewLogger() // set filename to date lumberjackLogger := &lumberjack.Logger{ diff --git a/content/en/docs/hertz/tutorials/framework-exten/log/zap.md b/content/en/docs/hertz/tutorials/framework-exten/log/zap.md index 42b0b9a2e0..b4c483ad3d 100644 --- a/content/en/docs/hertz/tutorials/framework-exten/log/zap.md +++ b/content/en/docs/hertz/tutorials/framework-exten/log/zap.md @@ -143,7 +143,7 @@ func main() { Function Signature: ```go -func WithCoreLevel(lvl zap.AtomicLevel) Option +func WithCoreLevel(lvl zap.AtomicLevel) Option ``` Sample code: @@ -206,7 +206,7 @@ func main() { Function Signature: ```go -func WithZapOptions(opts ...zap.Option) Option +func WithZapOptions(opts ...zap.Option) Option ``` Sample code: @@ -323,7 +323,7 @@ func main() { return } } - + logger := hertzzap.NewLogger() // Provides compression and deletion lumberjackLogger := &lumberjack.Logger{ diff --git a/content/en/docs/hertz/tutorials/framework-exten/log/zerolog.md b/content/en/docs/hertz/tutorials/framework-exten/log/zerolog.md index 9b1bcf3219..c9ea13b399 100644 --- a/content/en/docs/hertz/tutorials/framework-exten/log/zerolog.md +++ b/content/en/docs/hertz/tutorials/framework-exten/log/zerolog.md @@ -141,7 +141,7 @@ func main() { Function Signature: ```go -func WithOutput(out io.Writer) Opt +func WithOutput(out io.Writer) Opt ``` Sample code: @@ -168,7 +168,7 @@ func main() { Function Signature: ```go -func WithLevel(level hlog.Level) Opt +func WithLevel(level hlog.Level) Opt ``` Sample code: @@ -195,7 +195,7 @@ func main() { Function Signature: ```go -func WithField(name string, value interface{}) Opt +func WithField(name string, value interface{}) Opt ``` Sample code: @@ -235,7 +235,7 @@ func main() { Function Signature: ```go -func WithFields(fields map[string]interface{}) Opt +func WithFields(fields map[string]interface{}) Opt ``` Sample code: @@ -264,7 +264,7 @@ func main() { Function Signature: ```go -func WithTimestamp() Opt +func WithTimestamp() Opt ``` Sample code: @@ -289,7 +289,7 @@ func main() { Function Signature: ```go -func WithFormattedTimestamp(format string) Opt +func WithFormattedTimestamp(format string) Opt ``` Sample code: @@ -315,7 +315,7 @@ func main() { Function Signature: ```go -func WithCaller() Opt +func WithCaller() Opt ``` Sample code: @@ -366,7 +366,7 @@ After calling the `CallerWithSkipFrameCount` method, a new Context structure is Function Signature: ```go -func WithCallerSkipFrameCount(skipFrameCount int) Opt +func WithCallerSkipFrameCount(skipFrameCount int) Opt ``` Sample code: @@ -390,7 +390,7 @@ func main() { Function Signature: ```go -func WithHook(hook zerolog.Hook) Opt +func WithHook(hook zerolog.Hook) Opt ``` Sample code: diff --git a/content/en/docs/hertz/tutorials/framework-exten/monitor.md b/content/en/docs/hertz/tutorials/framework-exten/monitor.md index 3f29102bb0..f04707fbc2 100644 --- a/content/en/docs/hertz/tutorials/framework-exten/monitor.md +++ b/content/en/docs/hertz/tutorials/framework-exten/monitor.md @@ -5,7 +5,6 @@ date: 2022-06-22 weight: 1 keywords: ["Monitoring Extension"] description: "Monitoring extension provided by Hertz." - --- If you want to get more detailed monitoring data, e.g. message packet size, or want to adopt other data source, e.g. InfluxDB, you can implement the `Trace` interface according to your requirements and inject it by `WithTracer` Option. diff --git a/content/en/docs/hertz/tutorials/framework-exten/network-lib.md b/content/en/docs/hertz/tutorials/framework-exten/network-lib.md index efa30e2799..d2f140650a 100644 --- a/content/en/docs/hertz/tutorials/framework-exten/network-lib.md +++ b/content/en/docs/hertz/tutorials/framework-exten/network-lib.md @@ -2,9 +2,14 @@ title: "Network Library Extensions" linkTitle: "Network Library Extensions" weight: 4 -keywords: ["Network Library Extensions", "network.Conn", "network.StreamConn", "network.Dialer"] +keywords: + [ + "Network Library Extensions", + "network.Conn", + "network.StreamConn", + "network.Dialer", + ] description: "Network Library Extensions provided by Hertz." - --- Hertz provides the ability to extend the network library. If users need to replace with other network libraries, they can implement the corresponding interfaces according to their needs. Server needs to implement the `network.Conn` or the `network.StreamConn` interface, Client needs to implement the `network.Dialer` interface. @@ -124,13 +129,13 @@ type Stream interface { type ReceiveStream interface { StreamID() int64 io.Reader - + // CancelRead aborts receiving on this stream. // It will ask the peer to stop transmitting stream data. // Read will unblock immediately, and future Read calls will fail. // When called multiple times or after reading the io.EOF it is a no-op. CancelRead(err ApplicationError) - + // SetReadDeadline sets the deadline for future Read calls and // any currently-blocked Read call. // A zero value for t means Read will not time out. @@ -157,7 +162,7 @@ type SendStream interface { // It must not be called concurrently with Write. // It must not be called after calling CancelWrite. io.Closer - + // The Context is canceled as soon as the write-side of the stream is closed. // This happens when Close() or CancelWrite() is called, or when the peer // cancels the read-side of their stream. diff --git a/content/en/docs/hertz/tutorials/framework-exten/protocol.md b/content/en/docs/hertz/tutorials/framework-exten/protocol.md index 09f0d5ab30..6ca56362ca 100644 --- a/content/en/docs/hertz/tutorials/framework-exten/protocol.md +++ b/content/en/docs/hertz/tutorials/framework-exten/protocol.md @@ -2,7 +2,8 @@ title: "Protocol extension" linkTitle: "Protocol extension" weight: 5 -keywords: ["Protocol extension", "protocol.Server", "protocol.StreamServer", "HTTP"] +keywords: + ["Protocol extension", "protocol.Server", "protocol.StreamServer", "HTTP"] description: "Protocol extensions provided by Hertz." --- diff --git a/content/en/docs/hertz/tutorials/framework-exten/response_writer.md b/content/en/docs/hertz/tutorials/framework-exten/response_writer.md index 4863a8097a..a46330109b 100644 --- a/content/en/docs/hertz/tutorials/framework-exten/response_writer.md +++ b/content/en/docs/hertz/tutorials/framework-exten/response_writer.md @@ -3,9 +3,8 @@ title: "Response Writer Extension" linkTitle: "Response Writer Extension" date: 2023-09-22 weight: 6 -keywords: [ "Response Writer Extension", "Response.HijackWriter" ] +keywords: ["Response Writer Extension", "Response.HijackWriter"] description: "Response Writer Extension provided by Hertz." - --- According to Hertz's [layered architecture](/zh/docs/hertz/overview/), the actual write @@ -52,8 +51,8 @@ ctx.Response.HijackWriter(**yourResponseWriter**) ## Supported Response Writer Extension - `ChunkedBodyWriter`: Hertz provides `NewChunkedBodyWriter` to create a response writer which allow users to flush chunk immediately during -the handler process, it is defined under `pkg/protocol/http1/resp/writer`, and you can implement your own response -writer. + the handler process, it is defined under `pkg/protocol/http1/resp/writer`, and you can implement your own response + writer. ### ChunkedBodyWriter diff --git a/content/en/docs/hertz/tutorials/framework-exten/service_discovery.md b/content/en/docs/hertz/tutorials/framework-exten/service_discovery.md index 27545a0551..89ac2d1f18 100644 --- a/content/en/docs/hertz/tutorials/framework-exten/service_discovery.md +++ b/content/en/docs/hertz/tutorials/framework-exten/service_discovery.md @@ -2,7 +2,13 @@ title: "Service Registration and Service Discovery Extensions" date: 2022-08-14 weight: 3 -keywords: ["Service Registration and Service Discovery Extensions", "Service Registration Extension", "Service Discovery Extension", "Load Balancing Extension"] +keywords: + [ + "Service Registration and Service Discovery Extensions", + "Service Registration Extension", + "Service Discovery Extension", + "Load Balancing Extension", + ] description: "Service Registration and Service Discovery Extensions provided by Hertz." --- diff --git a/content/en/docs/hertz/tutorials/observability/_index.md b/content/en/docs/hertz/tutorials/observability/_index.md index 51c2f59b67..ed1f37a4df 100644 --- a/content/en/docs/hertz/tutorials/observability/_index.md +++ b/content/en/docs/hertz/tutorials/observability/_index.md @@ -4,5 +4,4 @@ linkTitle: "Observability" weight: 3 keywords: ["Observability", "Log", "Tracing", "Monitoring", "OpenTelemetry"] description: "The observability capability provided by Hertz." - --- diff --git a/content/en/docs/hertz/tutorials/observability/log.md b/content/en/docs/hertz/tutorials/observability/log.md index f690b1cfbf..ee6c58b654 100644 --- a/content/en/docs/hertz/tutorials/observability/log.md +++ b/content/en/docs/hertz/tutorials/observability/log.md @@ -4,7 +4,6 @@ date: 2022-05-23 weight: 1 keywords: ["Log", "logLevel"] description: "Hertz provides logging capabilities." - --- Hertz provides a default way to print logs in the standard output. It also provides several global functions, such as `hlog.Info`, `hlog.Errorf`, `hlog.CtxTracef`, etc., which are implemented in `pkg/common/hlog`, to call the corresponding methods of the default logger. diff --git a/content/en/docs/hertz/tutorials/observability/monitoring.md b/content/en/docs/hertz/tutorials/observability/monitoring.md index 8727fae469..237be83ac7 100644 --- a/content/en/docs/hertz/tutorials/observability/monitoring.md +++ b/content/en/docs/hertz/tutorials/observability/monitoring.md @@ -5,7 +5,6 @@ date: 2022-06-21 weight: 4 keywords: ["Monitoring"] description: "Hertz provides monitoring capabilities." - --- The framework doesn't provide any monitoring, but only provides a `Tracer` interface. This interface can be implemented by yourself and be injected via `WithTracer` Option. diff --git a/content/en/docs/hertz/tutorials/service-governance/_index.md b/content/en/docs/hertz/tutorials/service-governance/_index.md index 593f6f9de5..d2fbbc0054 100644 --- a/content/en/docs/hertz/tutorials/service-governance/_index.md +++ b/content/en/docs/hertz/tutorials/service-governance/_index.md @@ -2,7 +2,7 @@ title: "Service Governance" linkTitle: "Service Governance" weight: 4 -keywords: ["Service Governance", "Service Registration and Discovery", "Sentinel"] +keywords: + ["Service Governance", "Service Registration and Discovery", "Sentinel"] description: "Service governance provided by Hertz." - --- diff --git a/content/en/docs/hertz/tutorials/service-governance/service_discovery/_index.md b/content/en/docs/hertz/tutorials/service-governance/service_discovery/_index.md index b66d9ab1b8..7e293595ce 100644 --- a/content/en/docs/hertz/tutorials/service-governance/service_discovery/_index.md +++ b/content/en/docs/hertz/tutorials/service-governance/service_discovery/_index.md @@ -2,7 +2,18 @@ title: "Service Registration and Discovery" date: 2023-04-22 weight: 1 -keywords: ["Service Registration and Discovery", "nacos", "consul", "etcd", "eureka", "polaris", "servicecomb", "zookeeper", "redis"] +keywords: + [ + "Service Registration and Discovery", + "nacos", + "consul", + "etcd", + "eureka", + "polaris", + "servicecomb", + "zookeeper", + "redis", + ] description: "Service Registration and Discovery Extensions provided by Hertz." --- @@ -23,12 +34,12 @@ As of now, the supported service discovery extensions are Some optional configurations are provided to users when using service discovery. -| Configuration | Description | -| ---------------------- | --------------------------------------------------------- | +| Configuration | Description | +| ---------------------- | ------------------------------------------------------------------------------------------------------ | | WithSD | Used in conjunction with service discovery, this request uses service discovery when `true` is passed. | -| WithTag | Used in conjunction with service discovery to set Tag information. | -| WithCustomizedAddrs | Customize the address of the target instance. | -| WithLoadBalanceOptions | Configure load balancing options. | +| WithTag | Used in conjunction with service discovery to set Tag information. | +| WithCustomizedAddrs | Customize the address of the target instance. | +| WithLoadBalanceOptions | Configure load balancing options. | ### WithSD diff --git a/content/en/docs/hertz/tutorials/service-governance/service_discovery/consul.md b/content/en/docs/hertz/tutorials/service-governance/service_discovery/consul.md index 52ab321cea..9ccfe53133 100644 --- a/content/en/docs/hertz/tutorials/service-governance/service_discovery/consul.md +++ b/content/en/docs/hertz/tutorials/service-governance/service_discovery/consul.md @@ -1,206 +1,206 @@ ---- -title: "consul" -date: 2023-04-22 -weight: 3 -keywords: ["Service Registration and Discovery", "consul"] -description: "Service Registration and Discovery consul Extensions provided by Hertz." ---- - -## Install - -```go -go get github.com/hertz-contrib/registry/consul -``` - -## Service Registry - -### Option - -Consul extension provides option configuration in the service registry section. - -#### WithCheck - -Consul extension provides `WithCheck` to help users configure the `AgentServiceCheck` option in Consul. `defaultCheck()` is called by default. If not use, set `check.Timeout` to 5 seconds, `check.Internal` to 5 seconds, and `check.DeregisterCriticalServiceAfter` to 1 minute. - -Function signature: - -```go -func WithCheck(check *api.AgentServiceCheck) Option -``` - -Example: - -```go -func main() { - // ... - consulClient, err := consulapi.NewClient(config) - // ... - check := &consulapi.AgentServiceCheck{ - // ... - } - r := consul.NewConsulRegister(consulClient, consul.WithCheck(check)) - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -### NewConsulRegister - -`NewConsulRegister` uses consul to create a new service registry, which needs to be passed in a client, which is created with `NewClient`. The service registry configuration can be customized. - -Function signature: - -```go -func NewConsulRegister(consulClient *api.Client, opts ...Option) registry.Registry -``` - -Example: - -```go -func main() { - // ... - consulClient, err := consulapi.NewClient(config) - // ... - r := consul.NewConsulRegister(consulClient) - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -## Service Discovery - -### NewConsulResolver - -`NewConsulResolver` uses consul to create a new service discovery center, you need to pass in the client. The client is created using `NewClient`. The service discovery center configuration can be customized. - -Function signature: - -```go -func NewConsulResolver(consulClient *api.Client) discovery.Resolver -``` - -Example: - -```go -func main() { - // ... - consulClient, err := consulapi.NewClient(consulConfig) - if err != nil { - log.Fatal(err) - return - } - r := consul.NewConsulResolver(consulClient) - - cli, err := client.NewClient() - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) -} -``` - -## How to use - -### Server - -```go -import ( - "context" - "log" - - "github.com/cloudwego/hertz/pkg/app" - "github.com/cloudwego/hertz/pkg/app/server" - "github.com/cloudwego/hertz/pkg/app/server/registry" - "github.com/cloudwego/hertz/pkg/common/utils" - "github.com/cloudwego/hertz/pkg/protocol/consts" - consulapi "github.com/hashicorp/consul/api" - "github.com/hertz-contrib/registry/consul" -) - - -func main() { - // build a consul client - config := consulapi.DefaultConfig() - config.Address = "127.0.0.1:8500" - consulClient, err := consulapi.NewClient(config) - if err != nil { - log.Fatal(err) - return - } - // build a consul register with the consul client - r := consul.NewConsulRegister(consulClient) - - // run Hertz with the consul register - addr := "127.0.0.1:8888" - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { - ctx.JSON(consts.StatusOK, utils.H{"ping": "pong1"}) - }) - h.Spin() -} -``` - -### Client - -```go -import ( - "log" - - "github.com/cloudwego/hertz/pkg/app/client" - "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" - consulapi "github.com/hashicorp/consul/api" - "github.com/hertz-contrib/registry/consul" -) - -func main() { - // build a consul client - consulConfig := consulapi.DefaultConfig() - consulConfig.Address = "127.0.0.1:8500" - consulClient, err := consulapi.NewClient(consulConfig) - if err != nil { - log.Fatal(err) - return - } - // build a consul resolver with the consul client - r := consul.NewConsulResolver(consulClient) - - // build a hertz client with the consul resolver - cli, err := client.NewClient() - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) -} -``` - -## Configuration - -The configuration of Consul client and server can be customized, refer to the configuration of [consul](https://github.com/hashicorp/consul). - -## Complete Example - -For more, see [example](https://github.com/hertz-contrib/registry/tree/main/consul/example) . +--- +title: "consul" +date: 2023-04-22 +weight: 3 +keywords: ["Service Registration and Discovery", "consul"] +description: "Service Registration and Discovery consul Extensions provided by Hertz." +--- + +## Install + +```go +go get github.com/hertz-contrib/registry/consul +``` + +## Service Registry + +### Option + +Consul extension provides option configuration in the service registry section. + +#### WithCheck + +Consul extension provides `WithCheck` to help users configure the `AgentServiceCheck` option in Consul. `defaultCheck()` is called by default. If not use, set `check.Timeout` to 5 seconds, `check.Internal` to 5 seconds, and `check.DeregisterCriticalServiceAfter` to 1 minute. + +Function signature: + +```go +func WithCheck(check *api.AgentServiceCheck) Option +``` + +Example: + +```go +func main() { + // ... + consulClient, err := consulapi.NewClient(config) + // ... + check := &consulapi.AgentServiceCheck{ + // ... + } + r := consul.NewConsulRegister(consulClient, consul.WithCheck(check)) + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +### NewConsulRegister + +`NewConsulRegister` uses consul to create a new service registry, which needs to be passed in a client, which is created with `NewClient`. The service registry configuration can be customized. + +Function signature: + +```go +func NewConsulRegister(consulClient *api.Client, opts ...Option) registry.Registry +``` + +Example: + +```go +func main() { + // ... + consulClient, err := consulapi.NewClient(config) + // ... + r := consul.NewConsulRegister(consulClient) + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +## Service Discovery + +### NewConsulResolver + +`NewConsulResolver` uses consul to create a new service discovery center, you need to pass in the client. The client is created using `NewClient`. The service discovery center configuration can be customized. + +Function signature: + +```go +func NewConsulResolver(consulClient *api.Client) discovery.Resolver +``` + +Example: + +```go +func main() { + // ... + consulClient, err := consulapi.NewClient(consulConfig) + if err != nil { + log.Fatal(err) + return + } + r := consul.NewConsulResolver(consulClient) + + cli, err := client.NewClient() + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) +} +``` + +## How to use + +### Server + +```go +import ( + "context" + "log" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/protocol/consts" + consulapi "github.com/hashicorp/consul/api" + "github.com/hertz-contrib/registry/consul" +) + + +func main() { + // build a consul client + config := consulapi.DefaultConfig() + config.Address = "127.0.0.1:8500" + consulClient, err := consulapi.NewClient(config) + if err != nil { + log.Fatal(err) + return + } + // build a consul register with the consul client + r := consul.NewConsulRegister(consulClient) + + // run Hertz with the consul register + addr := "127.0.0.1:8888" + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { + ctx.JSON(consts.StatusOK, utils.H{"ping": "pong1"}) + }) + h.Spin() +} +``` + +### Client + +```go +import ( + "log" + + "github.com/cloudwego/hertz/pkg/app/client" + "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" + consulapi "github.com/hashicorp/consul/api" + "github.com/hertz-contrib/registry/consul" +) + +func main() { + // build a consul client + consulConfig := consulapi.DefaultConfig() + consulConfig.Address = "127.0.0.1:8500" + consulClient, err := consulapi.NewClient(consulConfig) + if err != nil { + log.Fatal(err) + return + } + // build a consul resolver with the consul client + r := consul.NewConsulResolver(consulClient) + + // build a hertz client with the consul resolver + cli, err := client.NewClient() + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) +} +``` + +## Configuration + +The configuration of Consul client and server can be customized, refer to the configuration of [consul](https://github.com/hashicorp/consul). + +## Complete Example + +For more, see [example](https://github.com/hertz-contrib/registry/tree/main/consul/example) . diff --git a/content/en/docs/hertz/tutorials/service-governance/service_discovery/etcd.md b/content/en/docs/hertz/tutorials/service-governance/service_discovery/etcd.md index 515867c440..ce106475c5 100644 --- a/content/en/docs/hertz/tutorials/service-governance/service_discovery/etcd.md +++ b/content/en/docs/hertz/tutorials/service-governance/service_discovery/etcd.md @@ -1,396 +1,396 @@ ---- -title: "etcd" -date: 2023-10-18 -weight: 4 -keywords: ["Service Registration and Discovery", "etcd"] -description: "Service Registration and Discovery etcd Extensions provided by Hertz." ---- - -## Install - -```go -go get github.com/hertz-contrib/registry/etcd -``` - -## Service Registry - -### Option - -Etcd extension provides option configuration in the service registry section. - -#### WithTLSOpt - -Etcd extension provides `WithTLSOpt` to help users configure the `TLS` option in Etcd. - -Function signature: - -```go -func WithTLSOpt(certFile, keyFile, caFile string) Option -``` - -Example: - -```go -func main() { - r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}, - etcd.WithTLSOpt(certFile, keyFile, caFile), - ) - if err != nil { - panic(err) - } - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - // ... -} -``` - -#### WithAuthOpt - -Etcd extension provides `WithTLSOpt` to help users configure the `Username` and `Password` option in Etcd. - -Function signature: - -```go -func WithAuthOpt(username, password string) Option -``` - -Example: - -```go -func main() { - r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}, - etcd.WithAuthOpt("root","123456"), - ) - if err != nil { - panic(err) - } - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - // ... -} -``` - -#### Retry - -After the service is registered to `ETCD`, it will regularly check the status of the service. If any abnormal status is found, it will try to register the service again. `observeDelay` is the delay time for checking the service status under normal conditions, and `retryDelay` is the delay time for attempting to register the service after disconnecting. - -**Default Config** - -| Config Name | Default Value | Description | -| ------------------- | ---------------- | ------------------------------------------------------------ | -| WithMaxAttemptTimes | 5 | Used to set the maximum number of attempts, if 0, it means infinite attempts | -| WithObserveDelay | 30 * time.Second | Used to set the delay time for checking service status under normal connection conditions | -| WithRetryDelay | 10 * time.Second | Used to set the retry delay time after disconnecting | - -##### WithMaxAttemptTimes - -`WithMaxAttemptTimes` sets the maximum number of call attempt times, including the initial call. - -Function signature: - -```go -func WithMaxAttemptTimes(maxAttemptTimes uint) Option -``` - -Example: - -```go -func main() { - r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}, - etcd.WithMaxAttemptTimes(10), - ) - if err != nil { - panic(err) - } - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - // ... -} -``` - -##### WithObserveDelay - -`WithObserveDelay` sets the delay time for checking the service status under normal conditions. - -Function signature: - -```go -func WithObserveDelay(observeDelay time.Duration) Option -``` - -Example: - -```go -func main() { - r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}, - etcd.WithObserveDelay(20*time.Second), - ) - if err != nil { - panic(err) - } - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - // ... -} -``` - -##### WithRetryDelay - -`WithRetryDelay` sets the delay time of retry. - -Function signature: - -```go -func WithRetryDelay(t time.Duration) Option -``` - -Example: - -```go -func main() { - r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}, - etcd.WithRetryDelay(5*time.Second), - ) - if err != nil { - panic(err) - } - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - // ... -} -``` - -### NewEtcdRegistry - -`NewEtcdRegistry` uses etcd to create a new service registry, requires passing in the endpoint value. Customizable service registry configuration. - -Function signature: - -```go -func NewEtcdRegistry(endpoints []string, opts ...Option) (registry.Registry, error) -``` - -Example: - -```go -func main() { - r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}) - if err != nil { - panic(err) - } - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - // ... -} -``` - -## Service Discovery - -### Option - -Etcd extension provides option configuration in the service discovery section. - -#### WithTLSOpt - -Etcd extension provides `WithTLSOpt` to help users configure the `TLS` option in Etcd. - -Function signature: - -```go -func WithTLSOpt(certFile, keyFile, caFile string) Option -``` - -Example: - -```go -func main() { - cli, err := client.NewClient() - if err != nil { - panic(err) - } - r, err := etcd.NewEtcdResolver([]string{"127.0.0.1:2379"}, - etcd.WithTLSOpt(certFile, keyFile, caFile), - ) - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - // ... -} -``` - -#### WithAuthOpt - -Etcd extension provides `WithTLSOpt` to help users configure the `Username` and `Password` option in Etcd. - -Function signature: - -```go -func WithAuthOpt(username, password string) Option -``` - -Example: - -```go -func main() { - cli, err := client.NewClient() - if err != nil { - panic(err) - } - r, err := etcd.NewEtcdResovler([]string{"127.0.0.1:2379"}, - etcd.WithAuthOpt("root","123456"), - ) - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - // ... -} -``` - -### NewEtcdResolver - -`NewEtcdResolver` uses etcd to create a new service discovery center, needs to pass in the endpoint value. You can customize the client configuration and pass `New` to create a new client. Customize the service discovery center configuration. - -Function signature: - -```go -func NewEtcdResolver(endpoints []string, opts ...Option) (discovery.Resolver, error) -``` - -Example: - -```go -func main() { - cli, err := client.NewClient() - if err != nil { - panic(err) - } - r, err := etcd.NewEtcdResolver([]string{"127.0.0.1:2379"}) - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - // ... -} -``` - -## How to use - -### Server - -```go -import ( - "context" - - "github.com/cloudwego/hertz/pkg/app" - "github.com/cloudwego/hertz/pkg/app/server" - "github.com/cloudwego/hertz/pkg/app/server/registry" - "github.com/cloudwego/hertz/pkg/common/utils" - "github.com/cloudwego/hertz/pkg/protocol/consts" - "github.com/hertz-contrib/registry/etcd" -) - -func main() { - r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}) - if err != nil { - panic(err) - } - addr := "127.0.0.1:8888" - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - h.GET("/ping", func(_ context.Context, ctx *app.RequestContext) { - ctx.JSON(consts.StatusOK, utils.H{"ping": "pong2"}) - }) - h.Spin() -} -``` - -### Client - -```go -import ( - "context" - - "github.com/cloudwego/hertz/pkg/app/client" - "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" - "github.com/cloudwego/hertz/pkg/common/config" - "github.com/cloudwego/hertz/pkg/common/hlog" - "github.com/hertz-contrib/registry/etcd" -) - -func main() { - cli, err := client.NewClient() - if err != nil { - panic(err) - } - r, err := etcd.NewEtcdResolver([]string{"127.0.0.1:2379"}) - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - for i := 0; i < 10; i++ { - status, body, err := cli.Get(context.Background(), nil, "http://hertz.test.demo/ping", config.WithSD(true)) - if err != nil { - hlog.Fatal(err) - } - hlog.Infof("HERTZ: code=%d,body=%s", status, string(body)) - } -} -``` - -## Configuration - -The configuration of Etcd client and server can be customized, refer to the configuration of [etcd-client](https://pkg.go.dev/go.etcd.io/etcd/client/v3). - -## Complete Example - -For more, see [example](https://github.com/hertz-contrib/registry/tree/main/etcd/example) . +--- +title: "etcd" +date: 2023-10-18 +weight: 4 +keywords: ["Service Registration and Discovery", "etcd"] +description: "Service Registration and Discovery etcd Extensions provided by Hertz." +--- + +## Install + +```go +go get github.com/hertz-contrib/registry/etcd +``` + +## Service Registry + +### Option + +Etcd extension provides option configuration in the service registry section. + +#### WithTLSOpt + +Etcd extension provides `WithTLSOpt` to help users configure the `TLS` option in Etcd. + +Function signature: + +```go +func WithTLSOpt(certFile, keyFile, caFile string) Option +``` + +Example: + +```go +func main() { + r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}, + etcd.WithTLSOpt(certFile, keyFile, caFile), + ) + if err != nil { + panic(err) + } + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + // ... +} +``` + +#### WithAuthOpt + +Etcd extension provides `WithTLSOpt` to help users configure the `Username` and `Password` option in Etcd. + +Function signature: + +```go +func WithAuthOpt(username, password string) Option +``` + +Example: + +```go +func main() { + r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}, + etcd.WithAuthOpt("root","123456"), + ) + if err != nil { + panic(err) + } + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + // ... +} +``` + +#### Retry + +After the service is registered to `ETCD`, it will regularly check the status of the service. If any abnormal status is found, it will try to register the service again. `observeDelay` is the delay time for checking the service status under normal conditions, and `retryDelay` is the delay time for attempting to register the service after disconnecting. + +**Default Config** + +| Config Name | Default Value | Description | +| ------------------- | ----------------- | ----------------------------------------------------------------------------------------- | +| WithMaxAttemptTimes | 5 | Used to set the maximum number of attempts, if 0, it means infinite attempts | +| WithObserveDelay | 30 \* time.Second | Used to set the delay time for checking service status under normal connection conditions | +| WithRetryDelay | 10 \* time.Second | Used to set the retry delay time after disconnecting | + +##### WithMaxAttemptTimes + +`WithMaxAttemptTimes` sets the maximum number of call attempt times, including the initial call. + +Function signature: + +```go +func WithMaxAttemptTimes(maxAttemptTimes uint) Option +``` + +Example: + +```go +func main() { + r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}, + etcd.WithMaxAttemptTimes(10), + ) + if err != nil { + panic(err) + } + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + // ... +} +``` + +##### WithObserveDelay + +`WithObserveDelay` sets the delay time for checking the service status under normal conditions. + +Function signature: + +```go +func WithObserveDelay(observeDelay time.Duration) Option +``` + +Example: + +```go +func main() { + r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}, + etcd.WithObserveDelay(20*time.Second), + ) + if err != nil { + panic(err) + } + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + // ... +} +``` + +##### WithRetryDelay + +`WithRetryDelay` sets the delay time of retry. + +Function signature: + +```go +func WithRetryDelay(t time.Duration) Option +``` + +Example: + +```go +func main() { + r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}, + etcd.WithRetryDelay(5*time.Second), + ) + if err != nil { + panic(err) + } + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + // ... +} +``` + +### NewEtcdRegistry + +`NewEtcdRegistry` uses etcd to create a new service registry, requires passing in the endpoint value. Customizable service registry configuration. + +Function signature: + +```go +func NewEtcdRegistry(endpoints []string, opts ...Option) (registry.Registry, error) +``` + +Example: + +```go +func main() { + r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}) + if err != nil { + panic(err) + } + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + // ... +} +``` + +## Service Discovery + +### Option + +Etcd extension provides option configuration in the service discovery section. + +#### WithTLSOpt + +Etcd extension provides `WithTLSOpt` to help users configure the `TLS` option in Etcd. + +Function signature: + +```go +func WithTLSOpt(certFile, keyFile, caFile string) Option +``` + +Example: + +```go +func main() { + cli, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := etcd.NewEtcdResolver([]string{"127.0.0.1:2379"}, + etcd.WithTLSOpt(certFile, keyFile, caFile), + ) + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + // ... +} +``` + +#### WithAuthOpt + +Etcd extension provides `WithTLSOpt` to help users configure the `Username` and `Password` option in Etcd. + +Function signature: + +```go +func WithAuthOpt(username, password string) Option +``` + +Example: + +```go +func main() { + cli, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := etcd.NewEtcdResovler([]string{"127.0.0.1:2379"}, + etcd.WithAuthOpt("root","123456"), + ) + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + // ... +} +``` + +### NewEtcdResolver + +`NewEtcdResolver` uses etcd to create a new service discovery center, needs to pass in the endpoint value. You can customize the client configuration and pass `New` to create a new client. Customize the service discovery center configuration. + +Function signature: + +```go +func NewEtcdResolver(endpoints []string, opts ...Option) (discovery.Resolver, error) +``` + +Example: + +```go +func main() { + cli, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := etcd.NewEtcdResolver([]string{"127.0.0.1:2379"}) + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + // ... +} +``` + +## How to use + +### Server + +```go +import ( + "context" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/protocol/consts" + "github.com/hertz-contrib/registry/etcd" +) + +func main() { + r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}) + if err != nil { + panic(err) + } + addr := "127.0.0.1:8888" + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + h.GET("/ping", func(_ context.Context, ctx *app.RequestContext) { + ctx.JSON(consts.StatusOK, utils.H{"ping": "pong2"}) + }) + h.Spin() +} +``` + +### Client + +```go +import ( + "context" + + "github.com/cloudwego/hertz/pkg/app/client" + "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" + "github.com/cloudwego/hertz/pkg/common/config" + "github.com/cloudwego/hertz/pkg/common/hlog" + "github.com/hertz-contrib/registry/etcd" +) + +func main() { + cli, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := etcd.NewEtcdResolver([]string{"127.0.0.1:2379"}) + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + for i := 0; i < 10; i++ { + status, body, err := cli.Get(context.Background(), nil, "http://hertz.test.demo/ping", config.WithSD(true)) + if err != nil { + hlog.Fatal(err) + } + hlog.Infof("HERTZ: code=%d,body=%s", status, string(body)) + } +} +``` + +## Configuration + +The configuration of Etcd client and server can be customized, refer to the configuration of [etcd-client](https://pkg.go.dev/go.etcd.io/etcd/client/v3). + +## Complete Example + +For more, see [example](https://github.com/hertz-contrib/registry/tree/main/etcd/example) . diff --git a/content/en/docs/hertz/tutorials/service-governance/service_discovery/eureka.md b/content/en/docs/hertz/tutorials/service-governance/service_discovery/eureka.md index ce5f9c384c..5bb621ea94 100644 --- a/content/en/docs/hertz/tutorials/service-governance/service_discovery/eureka.md +++ b/content/en/docs/hertz/tutorials/service-governance/service_discovery/eureka.md @@ -1,268 +1,268 @@ ---- -title: "eureka" -date: 2023-04-22 -weight: 5 -keywords: ["Service Registration and Discovery", "eureka"] -description: "Service Registration and Discovery eureka Extensions provided by Hertz." ---- - -## Install - -```go -go get github.com/hertz-contrib/eureka -``` - -## Service Registry - -### NewEurekaRegistry - -`NewEurekaRegistry` uses eureka to create a new service registry, you need to pass the service Url into `NewConn` through a string slice, and also pass in the heartbeat interval. - -Function signature: - -```go -func NewEurekaRegistry(servers []string, heatBeatInterval time.Duration) *eurekaRegistry -``` - -Example: - -```go -func main() { - // ... - r := eureka.NewEurekaRegistry([]string{"http://127.0.0.1:8761/eureka"}, 40*time.Second) - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.discovery.eureka", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - //... -} -``` - -### NewEurekaRegistryFromConfig - -`NewEurekaRegistryFromConfig` uses eureka to create a new service registry, you need to pass in the configuration and call `NewConnFromConfig` , and also need to pass in the heartbeat interval. - -Function signature: - -```go -func NewEurekaRegistryFromConfig(config fargo.Config, heatBeatInterval time.Duration) *eurekaRegistry -``` - -Example: - -```go -func main() { - // ... - config := fargo.Config{ - // ... - } - r := eureka.NewEurekaRegistryFromConfig(config, 40*time.Second) - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.discovery.eureka", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - //... -} -``` - -### NewEurekaRegistryFromConn - -`NewEurekaRegistryFromConn` uses eureka to create a new service registry, you need to pass in conn directly, and also need to pass in the heartbeat interval. - -Function signature: - -```go -func NewEurekaRegistryFromConn(conn fargo.EurekaConnection, heatBeatInterval time.Duration) *eurekaRegistry -``` - -Example: - -```go -func main() { - // ... - conn := fargo.EurekaConnection{ - // ... - } - r := eureka.NewEurekaRegistryFromConn(conn, 40*time.Second) - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.discovery.eureka", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - //... -} -``` - -## Service Discovery - -### NewEurekaResolver - -`NewEurekaResolver` uses eureka to create a new service discovery center, you need to pass the service Url through a string slice to `NewConn`. - -Function signature: - -```go -func NewEurekaResolver(servers []string) *eurekaResolver -``` - -Example: - -```go -func main() { - cli, err := client.NewClient() - if err != nil { - hlog.Fatal(err) - return - } - r := eureka.NewEurekaResolver([]string{"http://127.0.0.1:8761/eureka"}) - - cli.Use(sd.Discovery(r)) - // ... -} -``` - -### NewEurekaResolverFromConfig - -`NewEurekaResolverFromConfig` uses eureka to create a new service discovery center, requires passing in the configuration and calling `NewConnFromConfig`. - -Function signature: - -```go -func NewEurekaResolverFromConfig(config fargo.Config) *eurekaResolver -``` - -Example: - -```go -func main() { - // ... - config := fargo.Config{ - // ... - } - cli, err := client.NewClient() - if err != nil { - hlog.Fatal(err) - return - } - r := eureka.NewEurekaResolverFromConfig(config) - - cli.Use(sd.Discovery(r)) - // ... -} -``` - -### NewEurekaResolverFromConn - -`NewEurekaResolverFromConn` uses eureka to create a new service discovery center, which needs to be passed directly to conn. - -Function signature: - -```go -func NewEurekaResolverFromConn(conn fargo.EurekaConnection) *eurekaResolver -``` - -Example: - -```go -func main() { - // ... - conn := fargo.EurekaConnection{ - // ... - } - cli, err := client.NewClient() - if err != nil { - hlog.Fatal(err) - return - } - r := eureka.NewEurekaResolverFromConn(conn) - - cli.Use(sd.Discovery(r)) - // ... -} -``` - -## How to use - -### Server - -```go -import ( - "context" - "time" - - "github.com/cloudwego/hertz/pkg/app" - "github.com/cloudwego/hertz/pkg/app/server" - "github.com/cloudwego/hertz/pkg/app/server/registry" - "github.com/cloudwego/hertz/pkg/common/utils" - "github.com/cloudwego/hertz/pkg/protocol/consts" - "github.com/hertz-contrib/registry/eureka" -) - -func main() { - addr := "127.0.0.1:8888" - r := eureka.NewEurekaRegistry([]string{"http://127.0.0.1:8761/eureka"}, 40*time.Second) - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.discovery.eureka", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { - ctx.JSON(consts.StatusOK, utils.H{"ping": "pong2"}) - }) - h.Spin() -} -``` - -### Client - -```go -import ( - "context" - - "github.com/cloudwego/hertz/pkg/app/client" - "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" - "github.com/cloudwego/hertz/pkg/common/config" - "github.com/cloudwego/hertz/pkg/common/hlog" - "github.com/hertz-contrib/registry/seureka" -) - -func main() { - cli, err := client.NewClient() - if err != nil { - hlog.Fatal(err) - return - } - r := eureka.NewEurekaResolver([]string{"http://127.0.0.1:8761/eureka"}) - - cli.Use(sd.Discovery(r)) - for i := 0; i < 10; i++ { - status, body, err := cli.Get(context.Background(), nil, "http://hertz.discovery.eureka/ping", config.WithSD(true)) - if err != nil { - hlog.Fatal(err) - } - hlog.Infof("code=%d,body=%s", status, string(body)) - } -} -``` - -## Configuration - -This project uses [fargo](https://github.com/hudl/fargo) as eureka client. You should refer to [fargo](https://github.com/hudl/fargo) documentation for advanced configuration. - -## Complete Example - -For more, see [example](https://github.com/hertz-contrib/registry/tree/main/eureka/example) . +--- +title: "eureka" +date: 2023-04-22 +weight: 5 +keywords: ["Service Registration and Discovery", "eureka"] +description: "Service Registration and Discovery eureka Extensions provided by Hertz." +--- + +## Install + +```go +go get github.com/hertz-contrib/eureka +``` + +## Service Registry + +### NewEurekaRegistry + +`NewEurekaRegistry` uses eureka to create a new service registry, you need to pass the service Url into `NewConn` through a string slice, and also pass in the heartbeat interval. + +Function signature: + +```go +func NewEurekaRegistry(servers []string, heatBeatInterval time.Duration) *eurekaRegistry +``` + +Example: + +```go +func main() { + // ... + r := eureka.NewEurekaRegistry([]string{"http://127.0.0.1:8761/eureka"}, 40*time.Second) + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.discovery.eureka", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + //... +} +``` + +### NewEurekaRegistryFromConfig + +`NewEurekaRegistryFromConfig` uses eureka to create a new service registry, you need to pass in the configuration and call `NewConnFromConfig` , and also need to pass in the heartbeat interval. + +Function signature: + +```go +func NewEurekaRegistryFromConfig(config fargo.Config, heatBeatInterval time.Duration) *eurekaRegistry +``` + +Example: + +```go +func main() { + // ... + config := fargo.Config{ + // ... + } + r := eureka.NewEurekaRegistryFromConfig(config, 40*time.Second) + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.discovery.eureka", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + //... +} +``` + +### NewEurekaRegistryFromConn + +`NewEurekaRegistryFromConn` uses eureka to create a new service registry, you need to pass in conn directly, and also need to pass in the heartbeat interval. + +Function signature: + +```go +func NewEurekaRegistryFromConn(conn fargo.EurekaConnection, heatBeatInterval time.Duration) *eurekaRegistry +``` + +Example: + +```go +func main() { + // ... + conn := fargo.EurekaConnection{ + // ... + } + r := eureka.NewEurekaRegistryFromConn(conn, 40*time.Second) + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.discovery.eureka", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + //... +} +``` + +## Service Discovery + +### NewEurekaResolver + +`NewEurekaResolver` uses eureka to create a new service discovery center, you need to pass the service Url through a string slice to `NewConn`. + +Function signature: + +```go +func NewEurekaResolver(servers []string) *eurekaResolver +``` + +Example: + +```go +func main() { + cli, err := client.NewClient() + if err != nil { + hlog.Fatal(err) + return + } + r := eureka.NewEurekaResolver([]string{"http://127.0.0.1:8761/eureka"}) + + cli.Use(sd.Discovery(r)) + // ... +} +``` + +### NewEurekaResolverFromConfig + +`NewEurekaResolverFromConfig` uses eureka to create a new service discovery center, requires passing in the configuration and calling `NewConnFromConfig`. + +Function signature: + +```go +func NewEurekaResolverFromConfig(config fargo.Config) *eurekaResolver +``` + +Example: + +```go +func main() { + // ... + config := fargo.Config{ + // ... + } + cli, err := client.NewClient() + if err != nil { + hlog.Fatal(err) + return + } + r := eureka.NewEurekaResolverFromConfig(config) + + cli.Use(sd.Discovery(r)) + // ... +} +``` + +### NewEurekaResolverFromConn + +`NewEurekaResolverFromConn` uses eureka to create a new service discovery center, which needs to be passed directly to conn. + +Function signature: + +```go +func NewEurekaResolverFromConn(conn fargo.EurekaConnection) *eurekaResolver +``` + +Example: + +```go +func main() { + // ... + conn := fargo.EurekaConnection{ + // ... + } + cli, err := client.NewClient() + if err != nil { + hlog.Fatal(err) + return + } + r := eureka.NewEurekaResolverFromConn(conn) + + cli.Use(sd.Discovery(r)) + // ... +} +``` + +## How to use + +### Server + +```go +import ( + "context" + "time" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/protocol/consts" + "github.com/hertz-contrib/registry/eureka" +) + +func main() { + addr := "127.0.0.1:8888" + r := eureka.NewEurekaRegistry([]string{"http://127.0.0.1:8761/eureka"}, 40*time.Second) + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.discovery.eureka", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { + ctx.JSON(consts.StatusOK, utils.H{"ping": "pong2"}) + }) + h.Spin() +} +``` + +### Client + +```go +import ( + "context" + + "github.com/cloudwego/hertz/pkg/app/client" + "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" + "github.com/cloudwego/hertz/pkg/common/config" + "github.com/cloudwego/hertz/pkg/common/hlog" + "github.com/hertz-contrib/registry/seureka" +) + +func main() { + cli, err := client.NewClient() + if err != nil { + hlog.Fatal(err) + return + } + r := eureka.NewEurekaResolver([]string{"http://127.0.0.1:8761/eureka"}) + + cli.Use(sd.Discovery(r)) + for i := 0; i < 10; i++ { + status, body, err := cli.Get(context.Background(), nil, "http://hertz.discovery.eureka/ping", config.WithSD(true)) + if err != nil { + hlog.Fatal(err) + } + hlog.Infof("code=%d,body=%s", status, string(body)) + } +} +``` + +## Configuration + +This project uses [fargo](https://github.com/hudl/fargo) as eureka client. You should refer to [fargo](https://github.com/hudl/fargo) documentation for advanced configuration. + +## Complete Example + +For more, see [example](https://github.com/hertz-contrib/registry/tree/main/eureka/example) . diff --git a/content/en/docs/hertz/tutorials/service-governance/service_discovery/nacos.md b/content/en/docs/hertz/tutorials/service-governance/service_discovery/nacos.md index 571e894271..5267cedeb8 100644 --- a/content/en/docs/hertz/tutorials/service-governance/service_discovery/nacos.md +++ b/content/en/docs/hertz/tutorials/service-governance/service_discovery/nacos.md @@ -1,387 +1,387 @@ ---- -title: "nacos" -date: 2023-04-22 -weight: 2 -keywords: ["Service Registration and Discovery", "nacos"] -description: "Service Registration and Discovery nacos Extensions provided by Hertz." ---- - -## Install - -- nacos-sdk-go v1 version - -```go -go get github.com/hertz-contrib/registry/nacos -``` - -- nacos-sdk-go v2 version - -```go -go get github.com/hertz-contrib/registry/nacos/v2 -``` - -## Service Registry - -### Option - -Nacos extension provides option configuration in the service registry section. - -#### WithRegistryCluster - -Nacos extension provides `WithRegistryCluster` to help users configure custom clusters. Defaults to "DEFAULT" . - -Function signature: - -```go -func WithRegistryCluster(cluster string) RegistryOption -``` - -Example: - -```go -func main() { - // ... - r, err := nacos.NewDefaultNacosRegistry( - nacos.WithRegistryCluster("Cluster123"), - ) - if err != nil { - log.Fatal(err) - return - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -#### WithRegistryGroup - -Nacos extension provides `WithRegistryGroup` to help users configure custom clusters. Defaults to "DEFAULT_GROUP" . - -Function signature: - -```go -func WithRegistryGroup(group string) RegistryOption -``` - -Example: - -```go -func main() { - // ... - r, err := nacos.NewDefaultNacosRegistry( - nacos.WithRegistryGroup("Group1"), - ) - if err != nil { - log.Fatal(err) - return - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -### NewDefaultNacosRegistry - -`NewDefaultNacosRegistry` creates a default service registry using nacos. `NewDefaultNacosConfig` will be called to create a default client. By default, the RegionID is `cn-hangzhou`, the server address is `127.0.0.1`, the server port number is `8848`, and the service instance information will not be automatically preloaded into the local cache upon startup. Service registry configuration can be customized. - -Function signature: - -```go -func NewDefaultNacosRegistry(opts ...RegistryOption) (registry.Registry, error) -``` - -Example: - -```go -func main() { - // ... - r, err := nacos.NewDefaultNacosRegistry() - if err != nil { - log.Fatal(err) - return - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -### NewNacosRegistry - -`NewNacosRegistry` uses nacos to create a service registry that can configure clients, and needs to pass in self-configured clients. Customizable service registry configuration. - -Function signature: - -```go -func NewNacosRegistry(client naming_client.INamingClient, opts ...RegistryOption) registry.Registry -``` - -Example: - -```go -func main() { - // ... - cli, err := clients.NewNamingClient( - vo.NacosClientParam{ - ClientConfig: &cc, - ServerConfigs: sc, - }, - ) - // ... - r := nacos.NewNacosRegistry(cli) - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - // ... -} -``` - -## Service Discovery - -### Option - -Nacos extension provides option configuration in the service discovery section. - -#### WithRegistryCluster - -Nacos extension provides `WithRegistryCluster` to help users configure custom clusters. Defaults to "DEFAULT" . - -Function signature: - -```go -func WithRegistryCluster(cluster string) RegistryOption -``` - -Example: - -```go -func main() { - client, err := client.NewClient() - if err != nil { - panic(err) - } - r, err := nacos.NewDefaultNacosResolver( - nacos.WithRegistryCluster("Cluster123"), - ) - if err != nil { - log.Fatal(err) - return - } - client.Use(sd.Discovery(r)) - // ... -} -``` - -#### WithRegistryGroup - -Nacos extension provides `WithRegistryGroup` to help users configure custom clusters. Defaults to "DEFAULT_GROUP" . - -Function signature: - -```go -func WithRegistryGroup(group string) RegistryOption -``` - -Example: - -```go -func main() { - client, err := client.NewClient() - if err != nil { - panic(err) - } - r, err := nacos.NewDefaultNacosResolver( - nacos.WithRegistryGroup("Group1"), - ) - if err != nil { - log.Fatal(err) - return - } - client.Use(sd.Discovery(r)) - // ... -} -``` - -### NewDefaultNacosResolver - -`NewDefaultNacosResolver` creates a default service discovery center using nacos. `NewDefaultNacosConfig` will be called to create a default client. By default, the RegionID is `cn-hangzhou`, the server address is `127.0.0.1`, the server port number is `8848`, and the service instance information will not be automatically preloaded into the local cache upon startup. Service registry configuration can be customized. - -Function signature: - -```go -func NewDefaultNacosResolver(opts ...ResolverOption) (discovery.Resolver, error) -``` - -Example: - -```go -func main() { - client, err := client.NewClient() - if err != nil { - panic(err) - } - r, err := nacos.NewDefaultNacosResolver() - if err != nil { - log.Fatal(err) - return - } - client.Use(sd.Discovery(r)) - // ... -} -``` - -### NewNacosResolver - -`NewNacosResolver` uses nacos to create a service discovery center with a configurable client, which needs to be passed in a self-configured client. Customizable Service Discovery Center configuration. - -Function signature: - -```go -func NewNacosResolver(cli naming_client.INamingClient, opts ...ResolverOption) discovery.Resolver -``` - -Example: - -```go -func main() { - cli, err := client.NewClient() - if err != nil { - panic(err) - } - // ... - nacosCli, err := clients.NewNamingClient( - vo.NacosClientParam{ - ClientConfig: &cc, - ServerConfigs: sc, - }) - if err != nil { - panic(err) - } - r := nacos.NewNacosResolver(nacosCli) - cli.Use(sd.Discovery(r)) - // ... -} -``` - -## How to use - -### Server - -- Use `server.WithRegistry` to set up registration extensions and registration information. - -```go -import ( - "context" - "log" - - "github.com/cloudwego/hertz/pkg/app" - "github.com/cloudwego/hertz/pkg/app/server" - "github.com/cloudwego/hertz/pkg/app/server/registry" - "github.com/cloudwego/hertz/pkg/common/utils" - "github.com/cloudwego/hertz/pkg/protocol/consts" - "github.com/hertz-contrib/registry/nacos" -) - -func main() { - addr := "127.0.0.1:8888" - r, err := nacos.NewDefaultNacosRegistry() - if err != nil { - log.Fatal(err) - return - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { - ctx.JSON(consts.StatusOK, utils.H{"ping": "pong"}) - }) - h.Spin() -} -``` - -### Client - -- Use the `sd.Discovery` built-in middleware to support incoming custom service discovery extensions as well as load balance extensions. -- When using service discovery, replace Host with the service name and use `config.WithSD` to confirm that this request uses service registration. - -```go -import ( - "context" - "log" - - "github.com/cloudwego/hertz/pkg/app/client" - "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" - "github.com/cloudwego/hertz/pkg/common/config" - "github.com/cloudwego/hertz/pkg/common/hlog" - "github.com/hertz-contrib/registry/nacos" -) - -func main() { - client, err := client.NewClient() - if err != nil { - panic(err) - } - r, err := nacos.NewDefaultNacosResolver() - if err != nil { - log.Fatal(err) - return - } - client.Use(sd.Discovery(r)) - for i := 0; i < 10; i++ { - status, body, err := client.Get(context.Background(), nil, "http://hertz.test.demo/ping", config.WithSD(true)) - if err != nil { - hlog.Fatal(err) - } - hlog.Infof("code=%d,body=%s\n", status, string(body)) - } -} -``` - -## Caution - -- The nacos/v2 version of hertz does not currently support creating multiple port examples in the same group multiple times. -- Service registration and discovery in nacos/v2 is compatible with previous versions. -- CustomLogger type in constant.ClientConfig has been removed in nacos-sdk-go v2. -- nacos/v2 only supports nacos 2.X version. - -## Configuration - -The configuration of Nacos client and server can be customized, refer to the configuration of [nacos-sdk-go](https://github.com/nacos-group/nacos-sdk-go) . - -## Complete Example - -For more, see [example](https://github.com/hertz-contrib/registry/tree/main/nacos/examples) . +--- +title: "nacos" +date: 2023-04-22 +weight: 2 +keywords: ["Service Registration and Discovery", "nacos"] +description: "Service Registration and Discovery nacos Extensions provided by Hertz." +--- + +## Install + +- nacos-sdk-go v1 version + +```go +go get github.com/hertz-contrib/registry/nacos +``` + +- nacos-sdk-go v2 version + +```go +go get github.com/hertz-contrib/registry/nacos/v2 +``` + +## Service Registry + +### Option + +Nacos extension provides option configuration in the service registry section. + +#### WithRegistryCluster + +Nacos extension provides `WithRegistryCluster` to help users configure custom clusters. Defaults to "DEFAULT" . + +Function signature: + +```go +func WithRegistryCluster(cluster string) RegistryOption +``` + +Example: + +```go +func main() { + // ... + r, err := nacos.NewDefaultNacosRegistry( + nacos.WithRegistryCluster("Cluster123"), + ) + if err != nil { + log.Fatal(err) + return + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +#### WithRegistryGroup + +Nacos extension provides `WithRegistryGroup` to help users configure custom clusters. Defaults to "DEFAULT_GROUP" . + +Function signature: + +```go +func WithRegistryGroup(group string) RegistryOption +``` + +Example: + +```go +func main() { + // ... + r, err := nacos.NewDefaultNacosRegistry( + nacos.WithRegistryGroup("Group1"), + ) + if err != nil { + log.Fatal(err) + return + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +### NewDefaultNacosRegistry + +`NewDefaultNacosRegistry` creates a default service registry using nacos. `NewDefaultNacosConfig` will be called to create a default client. By default, the RegionID is `cn-hangzhou`, the server address is `127.0.0.1`, the server port number is `8848`, and the service instance information will not be automatically preloaded into the local cache upon startup. Service registry configuration can be customized. + +Function signature: + +```go +func NewDefaultNacosRegistry(opts ...RegistryOption) (registry.Registry, error) +``` + +Example: + +```go +func main() { + // ... + r, err := nacos.NewDefaultNacosRegistry() + if err != nil { + log.Fatal(err) + return + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +### NewNacosRegistry + +`NewNacosRegistry` uses nacos to create a service registry that can configure clients, and needs to pass in self-configured clients. Customizable service registry configuration. + +Function signature: + +```go +func NewNacosRegistry(client naming_client.INamingClient, opts ...RegistryOption) registry.Registry +``` + +Example: + +```go +func main() { + // ... + cli, err := clients.NewNamingClient( + vo.NacosClientParam{ + ClientConfig: &cc, + ServerConfigs: sc, + }, + ) + // ... + r := nacos.NewNacosRegistry(cli) + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + // ... +} +``` + +## Service Discovery + +### Option + +Nacos extension provides option configuration in the service discovery section. + +#### WithRegistryCluster + +Nacos extension provides `WithRegistryCluster` to help users configure custom clusters. Defaults to "DEFAULT" . + +Function signature: + +```go +func WithRegistryCluster(cluster string) RegistryOption +``` + +Example: + +```go +func main() { + client, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := nacos.NewDefaultNacosResolver( + nacos.WithRegistryCluster("Cluster123"), + ) + if err != nil { + log.Fatal(err) + return + } + client.Use(sd.Discovery(r)) + // ... +} +``` + +#### WithRegistryGroup + +Nacos extension provides `WithRegistryGroup` to help users configure custom clusters. Defaults to "DEFAULT_GROUP" . + +Function signature: + +```go +func WithRegistryGroup(group string) RegistryOption +``` + +Example: + +```go +func main() { + client, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := nacos.NewDefaultNacosResolver( + nacos.WithRegistryGroup("Group1"), + ) + if err != nil { + log.Fatal(err) + return + } + client.Use(sd.Discovery(r)) + // ... +} +``` + +### NewDefaultNacosResolver + +`NewDefaultNacosResolver` creates a default service discovery center using nacos. `NewDefaultNacosConfig` will be called to create a default client. By default, the RegionID is `cn-hangzhou`, the server address is `127.0.0.1`, the server port number is `8848`, and the service instance information will not be automatically preloaded into the local cache upon startup. Service registry configuration can be customized. + +Function signature: + +```go +func NewDefaultNacosResolver(opts ...ResolverOption) (discovery.Resolver, error) +``` + +Example: + +```go +func main() { + client, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := nacos.NewDefaultNacosResolver() + if err != nil { + log.Fatal(err) + return + } + client.Use(sd.Discovery(r)) + // ... +} +``` + +### NewNacosResolver + +`NewNacosResolver` uses nacos to create a service discovery center with a configurable client, which needs to be passed in a self-configured client. Customizable Service Discovery Center configuration. + +Function signature: + +```go +func NewNacosResolver(cli naming_client.INamingClient, opts ...ResolverOption) discovery.Resolver +``` + +Example: + +```go +func main() { + cli, err := client.NewClient() + if err != nil { + panic(err) + } + // ... + nacosCli, err := clients.NewNamingClient( + vo.NacosClientParam{ + ClientConfig: &cc, + ServerConfigs: sc, + }) + if err != nil { + panic(err) + } + r := nacos.NewNacosResolver(nacosCli) + cli.Use(sd.Discovery(r)) + // ... +} +``` + +## How to use + +### Server + +- Use `server.WithRegistry` to set up registration extensions and registration information. + +```go +import ( + "context" + "log" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/protocol/consts" + "github.com/hertz-contrib/registry/nacos" +) + +func main() { + addr := "127.0.0.1:8888" + r, err := nacos.NewDefaultNacosRegistry() + if err != nil { + log.Fatal(err) + return + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { + ctx.JSON(consts.StatusOK, utils.H{"ping": "pong"}) + }) + h.Spin() +} +``` + +### Client + +- Use the `sd.Discovery` built-in middleware to support incoming custom service discovery extensions as well as load balance extensions. +- When using service discovery, replace Host with the service name and use `config.WithSD` to confirm that this request uses service registration. + +```go +import ( + "context" + "log" + + "github.com/cloudwego/hertz/pkg/app/client" + "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" + "github.com/cloudwego/hertz/pkg/common/config" + "github.com/cloudwego/hertz/pkg/common/hlog" + "github.com/hertz-contrib/registry/nacos" +) + +func main() { + client, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := nacos.NewDefaultNacosResolver() + if err != nil { + log.Fatal(err) + return + } + client.Use(sd.Discovery(r)) + for i := 0; i < 10; i++ { + status, body, err := client.Get(context.Background(), nil, "http://hertz.test.demo/ping", config.WithSD(true)) + if err != nil { + hlog.Fatal(err) + } + hlog.Infof("code=%d,body=%s\n", status, string(body)) + } +} +``` + +## Caution + +- The nacos/v2 version of hertz does not currently support creating multiple port examples in the same group multiple times. +- Service registration and discovery in nacos/v2 is compatible with previous versions. +- CustomLogger type in constant.ClientConfig has been removed in nacos-sdk-go v2. +- nacos/v2 only supports nacos 2.X version. + +## Configuration + +The configuration of Nacos client and server can be customized, refer to the configuration of [nacos-sdk-go](https://github.com/nacos-group/nacos-sdk-go) . + +## Complete Example + +For more, see [example](https://github.com/hertz-contrib/registry/tree/main/nacos/examples) . diff --git a/content/en/docs/hertz/tutorials/service-governance/service_discovery/polaris.md b/content/en/docs/hertz/tutorials/service-governance/service_discovery/polaris.md index e283c97e9c..25129a170f 100644 --- a/content/en/docs/hertz/tutorials/service-governance/service_discovery/polaris.md +++ b/content/en/docs/hertz/tutorials/service-governance/service_discovery/polaris.md @@ -1,173 +1,173 @@ ---- -title: "polaris" -date: 2023-04-22 -weight: 6 -keywords: ["Service Registration and Discovery", "polaris"] -description: "Service Registration and Discovery polaris Extensions provided by Hertz." ---- - -## Install - -```go -go get github.com/hertz-contrib/registry/polaris -``` - -## Service Registry - -### NewPolarisRegistry - -`NewPolarisRegistry` creates a new service registry using polaris, passing in a configuration file and calling `GetPolarisConfig` , using the default configuration if not passed in. - -Function signature: - -```go -func NewPolarisRegistry(configFile ...string) (Registry, error) -``` - -Example: - -```go -func main() { - r, err := polaris.NewPolarisRegistry(confPath) - if err != nil { - log.Fatal(err) - } - - Info := ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", "127.0.0.1:8888"), - Tags: map[string]string{ - "namespace": Namespace, - }, - } - h := server.Default(server.WithRegistry(r, Info), server.WithExitWaitTime(10*time.Second)) - // ... -} -``` - -## Service Discovery - -### NewPolarisResolver - -`NewPolarisResolver` uses polaris to create a new service discovery center, passing in a configuration file and calling `GetPolarisConfig` , using the default configuration if not passed in. - -Function signature: - -```go -func NewPolarisResolver(configFile ...string) (Resolver, error) -``` - -Example: - -```go -func main() { - r, err := polaris.NewPolarisResolver(confPath) - if err != nil { - log.Fatal(err) - } - - client, err := hclient.NewClient() - client.Use(sd.Discovery(r)) - //... -} -``` - -## How to use - -### Server - -```go -import ( - "context" - "log" - "time" - - "github.com/cloudwego/hertz/pkg/app" - "github.com/cloudwego/hertz/pkg/app/server" - "github.com/cloudwego/hertz/pkg/app/server/registry" - "github.com/cloudwego/hertz/pkg/common/utils" - "github.com/cloudwego/hertz/pkg/protocol/consts" - "github.com/hertz-contrib/registry/polaris" -) - -const ( - confPath = "polaris.yaml" - Namespace = "Polaris" - // At present,polaris server tag is v1.4.0,can't support auto create namespace, - // If you want to use a namespace other than default,Polaris ,before you register an instance, - // you should create the namespace at polaris console first. -) - -func main() { - r, err := polaris.NewPolarisRegistry(confPath) - - if err != nil { - log.Fatal(err) - } - - Info := ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", "127.0.0.1:8888"), - Tags: map[string]string{ - "namespace": Namespace, - }, - } - h := server.Default(server.WithRegistry(r, Info), server.WithExitWaitTime(10*time.Second)) - - h.GET("/hello", func(ctx context.Context, c *app.RequestContext) { - c.String(consts.StatusOK, "Hello,Hertz!") - }) - - h.Spin() -} -``` - -### Client - -```go -import ( - "context" - "log" - - hclient "github.com/cloudwego/hertz/pkg/app/client" - "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" - "github.com/cloudwego/hertz/pkg/common/config" - "github.com/cloudwego/hertz/pkg/common/hlog" - "github.com/hertz-contrib/registry/polaris" -) - -const ( - confPath = "polaris.yaml" - Namespace = "Polaris" - // At present,polaris server tag is v1.4.0,can't support auto create namespace, - // if you want to use a namespace other than default,Polaris ,before you register an instance, - // you should create the namespace at polaris console first. -) - -func main() { - r, err := polaris.NewPolarisResolver(confPath) - if err != nil { - log.Fatal(err) - } - - client, err := hclient.NewClient() - client.Use(sd.Discovery(r)) - - for i := 0; i < 10; i++ { - // config.WithTag sets the namespace tag for service discovery - status, body, err := client.Get(context.TODO(), nil, "http://hertz.test.demo/hello", config.WithSD(true), config.WithTag("namespace", Namespace)) - if err != nil { - hlog.Fatal(err) - } - hlog.Infof("code=%d,body=%s\n", status, body) - } -} -``` - -## Configuration - -The configuration of Polaris client and server can be customized, refer to the configuration of [polaris-go](https://pkg.go.dev/github.com/polarismesh/polaris-go/api#section-readme). - -## Complete Example - -For more, see [example](https://github.com/hertz-contrib/registry/tree/main/polaris/example) . +--- +title: "polaris" +date: 2023-04-22 +weight: 6 +keywords: ["Service Registration and Discovery", "polaris"] +description: "Service Registration and Discovery polaris Extensions provided by Hertz." +--- + +## Install + +```go +go get github.com/hertz-contrib/registry/polaris +``` + +## Service Registry + +### NewPolarisRegistry + +`NewPolarisRegistry` creates a new service registry using polaris, passing in a configuration file and calling `GetPolarisConfig` , using the default configuration if not passed in. + +Function signature: + +```go +func NewPolarisRegistry(configFile ...string) (Registry, error) +``` + +Example: + +```go +func main() { + r, err := polaris.NewPolarisRegistry(confPath) + if err != nil { + log.Fatal(err) + } + + Info := ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", "127.0.0.1:8888"), + Tags: map[string]string{ + "namespace": Namespace, + }, + } + h := server.Default(server.WithRegistry(r, Info), server.WithExitWaitTime(10*time.Second)) + // ... +} +``` + +## Service Discovery + +### NewPolarisResolver + +`NewPolarisResolver` uses polaris to create a new service discovery center, passing in a configuration file and calling `GetPolarisConfig` , using the default configuration if not passed in. + +Function signature: + +```go +func NewPolarisResolver(configFile ...string) (Resolver, error) +``` + +Example: + +```go +func main() { + r, err := polaris.NewPolarisResolver(confPath) + if err != nil { + log.Fatal(err) + } + + client, err := hclient.NewClient() + client.Use(sd.Discovery(r)) + //... +} +``` + +## How to use + +### Server + +```go +import ( + "context" + "log" + "time" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/protocol/consts" + "github.com/hertz-contrib/registry/polaris" +) + +const ( + confPath = "polaris.yaml" + Namespace = "Polaris" + // At present,polaris server tag is v1.4.0,can't support auto create namespace, + // If you want to use a namespace other than default,Polaris ,before you register an instance, + // you should create the namespace at polaris console first. +) + +func main() { + r, err := polaris.NewPolarisRegistry(confPath) + + if err != nil { + log.Fatal(err) + } + + Info := ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", "127.0.0.1:8888"), + Tags: map[string]string{ + "namespace": Namespace, + }, + } + h := server.Default(server.WithRegistry(r, Info), server.WithExitWaitTime(10*time.Second)) + + h.GET("/hello", func(ctx context.Context, c *app.RequestContext) { + c.String(consts.StatusOK, "Hello,Hertz!") + }) + + h.Spin() +} +``` + +### Client + +```go +import ( + "context" + "log" + + hclient "github.com/cloudwego/hertz/pkg/app/client" + "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" + "github.com/cloudwego/hertz/pkg/common/config" + "github.com/cloudwego/hertz/pkg/common/hlog" + "github.com/hertz-contrib/registry/polaris" +) + +const ( + confPath = "polaris.yaml" + Namespace = "Polaris" + // At present,polaris server tag is v1.4.0,can't support auto create namespace, + // if you want to use a namespace other than default,Polaris ,before you register an instance, + // you should create the namespace at polaris console first. +) + +func main() { + r, err := polaris.NewPolarisResolver(confPath) + if err != nil { + log.Fatal(err) + } + + client, err := hclient.NewClient() + client.Use(sd.Discovery(r)) + + for i := 0; i < 10; i++ { + // config.WithTag sets the namespace tag for service discovery + status, body, err := client.Get(context.TODO(), nil, "http://hertz.test.demo/hello", config.WithSD(true), config.WithTag("namespace", Namespace)) + if err != nil { + hlog.Fatal(err) + } + hlog.Infof("code=%d,body=%s\n", status, body) + } +} +``` + +## Configuration + +The configuration of Polaris client and server can be customized, refer to the configuration of [polaris-go](https://pkg.go.dev/github.com/polarismesh/polaris-go/api#section-readme). + +## Complete Example + +For more, see [example](https://github.com/hertz-contrib/registry/tree/main/polaris/example) . diff --git a/content/en/docs/hertz/tutorials/service-governance/service_discovery/redis.md b/content/en/docs/hertz/tutorials/service-governance/service_discovery/redis.md index bc83f3bf13..8e169cf6ce 100644 --- a/content/en/docs/hertz/tutorials/service-governance/service_discovery/redis.md +++ b/content/en/docs/hertz/tutorials/service-governance/service_discovery/redis.md @@ -1,531 +1,531 @@ ---- -title: "redis" -date: 2023-04-22 -weight: 9 -keywords: ["Service Registration and Discovery", "redis"] -description: "Service Registration and Discovery redis Extensions provided by Hertz." ---- - -## Install - -```go -go get github.com/hertz-contrib/registry/redis -``` - -## Service Registry - -### Option - -The Redis extension provides option configuration in the service registry section. - -#### WithExpireTime - -The Redis extension provides the `WithExpireTime` to set the expiration time (in seconds) for the key storing service information. The default is 60 seconds. - -**NOTE: Expiration time must be greater than refresh interval.** - -Function signature: - -```go -func WithExpireTime(time int) Option -``` - -Sample code: - -```go -func main() { - r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithExpireTime(10)) - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -#### WithRefreshInterval - -The Redis extension provides the `WithRefreshInterval` to set the expiration time refresh interval (in seconds) for the key storing service information. The default is 30 seconds. - -**NOTE: Refresh interval must be less than expiration time.** - -Function signature: - -```go -func WithRefreshInterval(interval int) Option -``` - -Sample code: - -```go -func main() { - r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithRereshInterval(5)) - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -#### WithPassword - -The Redis extension provides `WithPassword` to configure the redis password, which must match the password specified in the server configuration options. Default to empty. - -Function signature: - -```go -func WithPassword(password string) Option -``` - -Sample code: - -```go -func main() { - r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithPassword("123456")) - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -#### WithDB - -The Redis extension provides `WithDB` to configure the database to choose after connecting to the server. Default to 0. - -Function signature: - -```go -func WithDB(db int) Option -``` - -Sample code: - -```go -func main() { - r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithDB(1)) - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -#### WithTLSConfig - -The Redis extension provides `WithTLSConfig` configuration items for configuring TLS. - -Function signature: - -```go -func WithTLSConfig(t *tls.Config) Option -``` - -Sample code: - -```go -func main() { - r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithTLSConfig(&tls.Config{ - // ... - })) - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -#### WithDialer - -The Redis extension provides `WithDialer` to configure Dialer, Dialer will create a new network connection and take precedence over Network and Addr options. - -Function signature: - -```go -func WithDialer(dialer func(ctx context.Context, network, addr string) (net.Conn, error)) Option -``` - -Sample code: - -```go -func main() { - r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithDialer( - // ... - )) - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -#### WithReadTimeout - -The Redis extension provides `WithReadTimeout` to configure the read socket timeout time, the default is 3 seconds. - -Function signature: - -```go -func WithReadTimeout(t time.Duration) Option -``` - -Sample code: - -```go -func main() { - r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithReadTimeout(5*time.Second)) - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -#### WithWriteTimeout - -The Redis extension provides `WithWriteTimeout` to configure the write socket timeout time, the default is equivalent to `ReadTimeout`. - -Function signature: - -```go -func WithWriteTimeout(t time.Duration) Option -``` - -Sample code: - -```go -func main() { - r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithWriteTimeout(5*time.Second)) - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -### NewRedisRegistry - -`NewRedisRegistry` uses redis to create a new service registry and needs to pass in the target address. You can customize the client configuration and pass in `NewClient` to create a new client. - -Function signature: - -```go -func NewRedisRegistry(addr string, opts...Option) registry.Registry -``` - -Sample code: - -```go -func main() { - r := redis.NewRedisRegistry("127.0.0.1:6379") - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -## Service Discovery - -### Option - -Redis extension provides option configuration in the service discovery section. - -#### WithPassword - -The Redis extension provides `WithPassword` to configure the redis password, which must match the password specified in the server configuration options. Default to empty. - -Function signature: - -```go -func WithPassword(password string) Option -``` - -Sample code: - -```go -func main() { - cli, err := client.NewClient() - // ... - r := redis.NewRedisResolver("127.0.0.1:6379", redis.WithPassword("123456")) - cli.Use(sd.Discovery(r)) - // ... -} -``` - -#### WithDB - -The Redis extension provides `WithDB` to configure the database to choose after connecting to the server. Default to 0. - -Function signature: - -```go -func WithDB(db int) Option -``` - -Sample code: - -```go -func main() { - cli, err := client.NewClient() - // ... - r := redis.NewRedisResolver("127.0.0.1:6379", redis.WithDB(1)) - cli.Use(sd.Discovery(r)) - // ... -} -``` - -#### WithTLSConfig - -The Redis extension provides `WithTLSConfig` configuration items for configuring TLS. - -Function signature: - -```go -func WithTLSConfig(t *tls.Config) Option -``` - -Sample code: - -```go -func main() { - cli, err := client.NewClient() - // ... - r := redis.NewRedisResolver("127.0.0.1:6379", redis.WithTLSConfig(&tls.Config{ - // ... - })) - cli.Use(sd.Discovery(r)) - // ... -} -``` - -#### WithDialer - -The Redis extension provides `WithDialer` to configure Dialer, Dialer will create a new network connection and take precedence over Network and Addr options. - -Function signature: - -```go -func WithDialer(dialer func(ctx context.Context, network, addr string) (net.Conn, error)) Option -``` - -Sample code: - -```go -func main() { - cli, err := client.NewClient() - // ... - r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithDialer( - // ... - )) - cli.Use(sd.Discovery(r)) - // ... -} -``` - -#### WithReadTimeout - -The Redis extension provides `WithReadTimeout` to configure the read socket timeout time, the default is 3 seconds. - -Function signature: - -```go -func WithReadTimeout(t time.Duration) Option -``` - -Sample code: - -```go -func main() { - cli, err := client.NewClient() - // ... - r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithReadTimeout(5*time.Second)) - // ... - cli.Use(sd.Discovery(r)) - // ... -} -``` - -#### WithWriteTimeout - -The Redis extension provides `WithWriteTimeout` to configure the write socket timeout time, the default is equivalent to `ReadTimeout`. - -Function signature: - -```go -func WithWriteTimeout(t time.Duration) Option -``` - -Sample code: - -```go -func main() { - cli, err := client.NewClient() - // ... - r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithWriteTimeout(5*time.Second)) - // ... - cli.Use(sd.Discovery(r)) - // ... -} -``` - -### NewRedisResolver - -`NewRedisResolver` uses redis to create a new service discovery center, and needs to pass in the target address. You can customize the client configuration and pass in `NewClient` to create a new client. - -Function signature: - -```go -func NewRedisResolver(addr string, opts ...Option) discovery.Resolver -``` - -Sample code: - -```go -func main() { - cli, err := client.NewClient() - // ... - r := redis.NewRedisResolver("127.0.0.1:6379") - cli.Use(sd.Discovery(r)) - // ... -} -``` - -## How to use - -### Server - -```go -package main - -import ( - "context" - - "github.com/cloudwego/hertz/pkg/app" - "github.com/cloudwego/hertz/pkg/app/server" - "github.com/cloudwego/hertz/pkg/app/server/registry" - "github.com/cloudwego/hertz/pkg/common/utils" - "github.com/cloudwego/hertz/pkg/protocol/consts" - "github.com/hertz-contrib/registry/redis" -) - -func main() { - r := redis.NewRedisRegistry("127.0.0.1:6379") - addr := "127.0.0.1:8888" - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - h.GET("/ping", func(_ context.Context, ctx *app.RequestContext) { - ctx.JSON(consts.StatusOK, utils.H{"ping": "pong"}) - }) - h.Spin() -} -``` - -### Client - -```go -package main - -import ( - "context" - - "github.com/cloudwego/hertz/pkg/app/client" - "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" - "github.com/cloudwego/hertz/pkg/common/config" - "github.com/cloudwego/hertz/pkg/common/hlog" - "github.com/hertz-contrib/registry/redis" -) - -func main() { - cli, err := client.NewClient() - if err != nil { - panic(err) - } - r := redis.NewRedisResolver("127.0.0.1:6379") - cli.Use(sd.Discovery(r)) - for i := 0; i < 10; i++ { - status, body, err := cli.Get(context.Background(), nil, "http://hertz.test.demo/ping", config.WithSD(true)) - if err != nil { - hlog.Fatal(err) - } - hlog.Infof("HERTZ: code=%d, body=%s", status, string(body)) - } -} -``` - -## Configuration - -You can customize the configuration of redis client and server, refer to [go-redis](https://github.com/go-redis/redis) configuration. - -## Complete Example - -For more, see [example](https://github.com/hertz-contrib/registry/tree/main/redis/example). +--- +title: "redis" +date: 2023-04-22 +weight: 9 +keywords: ["Service Registration and Discovery", "redis"] +description: "Service Registration and Discovery redis Extensions provided by Hertz." +--- + +## Install + +```go +go get github.com/hertz-contrib/registry/redis +``` + +## Service Registry + +### Option + +The Redis extension provides option configuration in the service registry section. + +#### WithExpireTime + +The Redis extension provides the `WithExpireTime` to set the expiration time (in seconds) for the key storing service information. The default is 60 seconds. + +**NOTE: Expiration time must be greater than refresh interval.** + +Function signature: + +```go +func WithExpireTime(time int) Option +``` + +Sample code: + +```go +func main() { + r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithExpireTime(10)) + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +#### WithRefreshInterval + +The Redis extension provides the `WithRefreshInterval` to set the expiration time refresh interval (in seconds) for the key storing service information. The default is 30 seconds. + +**NOTE: Refresh interval must be less than expiration time.** + +Function signature: + +```go +func WithRefreshInterval(interval int) Option +``` + +Sample code: + +```go +func main() { + r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithRereshInterval(5)) + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +#### WithPassword + +The Redis extension provides `WithPassword` to configure the redis password, which must match the password specified in the server configuration options. Default to empty. + +Function signature: + +```go +func WithPassword(password string) Option +``` + +Sample code: + +```go +func main() { + r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithPassword("123456")) + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +#### WithDB + +The Redis extension provides `WithDB` to configure the database to choose after connecting to the server. Default to 0. + +Function signature: + +```go +func WithDB(db int) Option +``` + +Sample code: + +```go +func main() { + r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithDB(1)) + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +#### WithTLSConfig + +The Redis extension provides `WithTLSConfig` configuration items for configuring TLS. + +Function signature: + +```go +func WithTLSConfig(t *tls.Config) Option +``` + +Sample code: + +```go +func main() { + r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithTLSConfig(&tls.Config{ + // ... + })) + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +#### WithDialer + +The Redis extension provides `WithDialer` to configure Dialer, Dialer will create a new network connection and take precedence over Network and Addr options. + +Function signature: + +```go +func WithDialer(dialer func(ctx context.Context, network, addr string) (net.Conn, error)) Option +``` + +Sample code: + +```go +func main() { + r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithDialer( + // ... + )) + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +#### WithReadTimeout + +The Redis extension provides `WithReadTimeout` to configure the read socket timeout time, the default is 3 seconds. + +Function signature: + +```go +func WithReadTimeout(t time.Duration) Option +``` + +Sample code: + +```go +func main() { + r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithReadTimeout(5*time.Second)) + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +#### WithWriteTimeout + +The Redis extension provides `WithWriteTimeout` to configure the write socket timeout time, the default is equivalent to `ReadTimeout`. + +Function signature: + +```go +func WithWriteTimeout(t time.Duration) Option +``` + +Sample code: + +```go +func main() { + r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithWriteTimeout(5*time.Second)) + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +### NewRedisRegistry + +`NewRedisRegistry` uses redis to create a new service registry and needs to pass in the target address. You can customize the client configuration and pass in `NewClient` to create a new client. + +Function signature: + +```go +func NewRedisRegistry(addr string, opts...Option) registry.Registry +``` + +Sample code: + +```go +func main() { + r := redis.NewRedisRegistry("127.0.0.1:6379") + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +## Service Discovery + +### Option + +Redis extension provides option configuration in the service discovery section. + +#### WithPassword + +The Redis extension provides `WithPassword` to configure the redis password, which must match the password specified in the server configuration options. Default to empty. + +Function signature: + +```go +func WithPassword(password string) Option +``` + +Sample code: + +```go +func main() { + cli, err := client.NewClient() + // ... + r := redis.NewRedisResolver("127.0.0.1:6379", redis.WithPassword("123456")) + cli.Use(sd.Discovery(r)) + // ... +} +``` + +#### WithDB + +The Redis extension provides `WithDB` to configure the database to choose after connecting to the server. Default to 0. + +Function signature: + +```go +func WithDB(db int) Option +``` + +Sample code: + +```go +func main() { + cli, err := client.NewClient() + // ... + r := redis.NewRedisResolver("127.0.0.1:6379", redis.WithDB(1)) + cli.Use(sd.Discovery(r)) + // ... +} +``` + +#### WithTLSConfig + +The Redis extension provides `WithTLSConfig` configuration items for configuring TLS. + +Function signature: + +```go +func WithTLSConfig(t *tls.Config) Option +``` + +Sample code: + +```go +func main() { + cli, err := client.NewClient() + // ... + r := redis.NewRedisResolver("127.0.0.1:6379", redis.WithTLSConfig(&tls.Config{ + // ... + })) + cli.Use(sd.Discovery(r)) + // ... +} +``` + +#### WithDialer + +The Redis extension provides `WithDialer` to configure Dialer, Dialer will create a new network connection and take precedence over Network and Addr options. + +Function signature: + +```go +func WithDialer(dialer func(ctx context.Context, network, addr string) (net.Conn, error)) Option +``` + +Sample code: + +```go +func main() { + cli, err := client.NewClient() + // ... + r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithDialer( + // ... + )) + cli.Use(sd.Discovery(r)) + // ... +} +``` + +#### WithReadTimeout + +The Redis extension provides `WithReadTimeout` to configure the read socket timeout time, the default is 3 seconds. + +Function signature: + +```go +func WithReadTimeout(t time.Duration) Option +``` + +Sample code: + +```go +func main() { + cli, err := client.NewClient() + // ... + r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithReadTimeout(5*time.Second)) + // ... + cli.Use(sd.Discovery(r)) + // ... +} +``` + +#### WithWriteTimeout + +The Redis extension provides `WithWriteTimeout` to configure the write socket timeout time, the default is equivalent to `ReadTimeout`. + +Function signature: + +```go +func WithWriteTimeout(t time.Duration) Option +``` + +Sample code: + +```go +func main() { + cli, err := client.NewClient() + // ... + r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithWriteTimeout(5*time.Second)) + // ... + cli.Use(sd.Discovery(r)) + // ... +} +``` + +### NewRedisResolver + +`NewRedisResolver` uses redis to create a new service discovery center, and needs to pass in the target address. You can customize the client configuration and pass in `NewClient` to create a new client. + +Function signature: + +```go +func NewRedisResolver(addr string, opts ...Option) discovery.Resolver +``` + +Sample code: + +```go +func main() { + cli, err := client.NewClient() + // ... + r := redis.NewRedisResolver("127.0.0.1:6379") + cli.Use(sd.Discovery(r)) + // ... +} +``` + +## How to use + +### Server + +```go +package main + +import ( + "context" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/protocol/consts" + "github.com/hertz-contrib/registry/redis" +) + +func main() { + r := redis.NewRedisRegistry("127.0.0.1:6379") + addr := "127.0.0.1:8888" + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + h.GET("/ping", func(_ context.Context, ctx *app.RequestContext) { + ctx.JSON(consts.StatusOK, utils.H{"ping": "pong"}) + }) + h.Spin() +} +``` + +### Client + +```go +package main + +import ( + "context" + + "github.com/cloudwego/hertz/pkg/app/client" + "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" + "github.com/cloudwego/hertz/pkg/common/config" + "github.com/cloudwego/hertz/pkg/common/hlog" + "github.com/hertz-contrib/registry/redis" +) + +func main() { + cli, err := client.NewClient() + if err != nil { + panic(err) + } + r := redis.NewRedisResolver("127.0.0.1:6379") + cli.Use(sd.Discovery(r)) + for i := 0; i < 10; i++ { + status, body, err := cli.Get(context.Background(), nil, "http://hertz.test.demo/ping", config.WithSD(true)) + if err != nil { + hlog.Fatal(err) + } + hlog.Infof("HERTZ: code=%d, body=%s", status, string(body)) + } +} +``` + +## Configuration + +You can customize the configuration of redis client and server, refer to [go-redis](https://github.com/go-redis/redis) configuration. + +## Complete Example + +For more, see [example](https://github.com/hertz-contrib/registry/tree/main/redis/example). diff --git a/content/en/docs/hertz/tutorials/service-governance/service_discovery/servicecomb.md b/content/en/docs/hertz/tutorials/service-governance/service_discovery/servicecomb.md index 9d1faf8eab..ea7d21488a 100644 --- a/content/en/docs/hertz/tutorials/service-governance/service_discovery/servicecomb.md +++ b/content/en/docs/hertz/tutorials/service-governance/service_discovery/servicecomb.md @@ -1,470 +1,470 @@ ---- -title: "servicecomb" -date: 2023-04-22 -weight: 7 -keywords: ["Service Registration and Discovery", "servicecomb"] -description: "Service Registration and Discovery servicecomb Extensions provided by Hertz." ---- - -## Install - -```go -go get github.com/hertz-contrib/registry/servicecomb -``` - -## Service Registry - -### Option - -Servicecomb extension provides option configuration in the service registry section. - -#### WithAppId - -Servicecomb extension provides `WithAppId` to help users configure the AppId of Servicecomb. Defaults to "DEFAULT" . - -Function signature: - -```go -func WithAppId(appId string) RegistryOption -``` - -Example: - -```go -func main() { - // ... - r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, - servicecomb.WithAppId("appID"), - ) - if err != nil { - log.Fatal(err) - return - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.servicecomb.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -#### WithRegistryVersionRule - -Servicecomb extension provides `WithRegistryVersionRule` to help users configure the version requirements of Servicecomb. Defaults to 1.0.0 . - -Function signature: - -```go -func WithRegistryVersionRule(versionRule string) RegistryOption -``` - -Example: - -```go -func main() { - // ... - r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, - servicecomb.WithRegistryVersionRule("1.1.0"), - ) - if err != nil { - log.Fatal(err) - return - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.servicecomb.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -#### WithRegistryHostName - -Servicecomb extension provides `WithRegistryHostName` to help users configure Servicecomb's hostname. Defaults to "DEFAULT" . - -Function signature: - -```go -func WithRegistryHostName(hostName string) RegistryOption -``` - -Example: - -```go -func main() { - // ... - r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, - servicecomb.WithRegistryHostName("hostName"), - ) - if err != nil { - log.Fatal(err) - return - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.servicecomb.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -#### WithRegistryHeartbeatInterval - -Servicecomb extension provides `WithRegistryHeartbeatInterval` to help users configure the interval for sending heartbeat packets. Default is 5. - -Function signature: - -```go -func WithRegistryHeartbeatInterval(second int32) RegistryOption -``` - -Example: - -```go -func main() { - // ... - r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, - servicecomb.WithRegistryHeartbeatInterval(10), - ) - if err != nil { - log.Fatal(err) - return - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.servicecomb.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -### NewDefaultSCRegistry - -`NewDefaultSCRegistry` uses service-comb to create a default service registry, which needs to pass in the endpoint value. The service registry configuration can be customized. - -Function signature: - -```go -func NewDefaultSCRegistry(endPoints []string, opts ...RegistryOption) (registry.Registry, error) -``` - -Example: - -```go -func main() { - // ... - r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}) - if err != nil { - log.Fatal(err) - return - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.servicecomb.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -### NewSCRegistry - -`NewSCRegistry` uses service-comb to create a new service registry. It needs to pass in a custom client. Customizable service registry configuration. - -Function signature: - -```go -func NewSCRegistry(client *sc.Client, opts ...RegistryOption) registry.Registry -``` - -Example: - -```go -func main() { - client := &sc.Client{ - // ... - } - // ... - r, err := servicecomb.NewSCRegistry(client) - if err != nil { - log.Fatal(err) - return - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.servicecomb.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -## Service Discovery - -### Option - -Servicecomb extension provides option configuration in the service discovery section. - -#### WithAppId - -Servicecomb extension provides `WithAppId` to help users configure the AppId of Servicecomb. Defaults to "DEFAULT" . - -Function signature: - -```go -func WithResolverAppId(appId string) ResolverOption -``` - -Example: - -```go -func main() { - // ... - r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, - servicecomb.WithAppId("appID"), - ) - if err != nil { - panic(err) - } - cli, err := client.NewClient() - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - // ... -} -``` - -#### WithResolverVersionRule - -Servicecomb extension provides `WithResolverVersionRule` to help users configure Servicecomb's version requirements. Defaults to latest . - -Function signature: - -```go -func WithResolverVersionRule(versionRule string) ResolverOption -``` - -Example: - -```go -func main() { - // ... - r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, - servicecomb.WithResolverVersionRule("1.0.0"), - ) - if err != nil { - panic(err) - } - cli, err := client.NewClient() - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - // ... -} -``` - -#### WithResolverConsumerId - -Servicecomb extension provides `WithResolverConsumerId` to help users configure Servicecomb's ConsumerId . Default is empty . - -Function signature: - -```go -func WithResolverConsumerId(consumerId string) ResolverOption -``` - -Example: - -```go -func main() { - // ... - r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, - servicecomb.WithResolverConsumerId("1"), - ) - if err != nil { - panic(err) - } - cli, err := client.NewClient() - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - // ... -} -``` - -### NewDefaultSCResolver - -`NewDefaultSCResolver` uses service-comb to create a default service discovery center, which needs to pass in the endpoint value. Service discovery center configuration can be customized. - -Function signature: - -```go -func NewDefaultSCResolver(endPoints []string, opts ...ResolverOption) (discovery.Resolver, error) -``` - -Example: - -```go -func main() { - // ... - r, err := servicecomb.NewDefaultSCResolver([]string{scAddr}) - if err != nil { - panic(err) - } - cli, err := client.NewClient() - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - // ... -} -``` - -### NewSCResolver - -`NewSCReslover` uses service-comb to create a new service discovery center. It needs to pass in a custom client. The configuration of the service discovery center can be customized. - -Function signature: - -```go -func NewSCResolver(cli *sc.Client, opts ...ResolverOption) discovery.Resolver -``` - -Example: - -```go -func main() { - client := &sc.Client{ - // ... - } - // ... - r, err := servicecomb.NewSCResolver(client) - if err != nil { - panic(err) - } - cli, err := client.NewClient() - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - // ... -} -``` - -## How to use - -### Server - -```go -import ( - "context" - "log" - "sync" - - "github.com/cloudwego/hertz/pkg/app" - "github.com/cloudwego/hertz/pkg/app/server" - "github.com/cloudwego/hertz/pkg/app/server/registry" - "github.com/cloudwego/hertz/pkg/common/utils" - "github.com/cloudwego/hertz/pkg/protocol/consts" - "github.com/hertz-contrib/registry/servicecomb" -) - -func main() { - const scAddr = "127.0.0.1:30100" - const addr = "127.0.0.1:8701" - r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}) - if err != nil { - log.Fatal(err) - return - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.servicecomb.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - - h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { - ctx.JSON(consts.StatusOK, utils.H{"ping": "pong1"}) - }) - h.Spin() -} -``` - -### Client - -```go -import ( - "context" - - "github.com/cloudwego/hertz/pkg/app/client" - "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" - "github.com/cloudwego/hertz/pkg/common/config" - "github.com/cloudwego/hertz/pkg/common/hlog" - "github.com/hertz-contrib/registry/servicecomb" -) - -func main() { - const scAddr = "127.0.0.1:30100" - // build a servicecomb resolver - r, err := servicecomb.NewDefaultSCResolver([]string{scAddr}) - if err != nil { - panic(err) - } - // build a hertz client with the servicecomb resolver - cli, err := client.NewClient() - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - for i := 0; i < 10; i++ { - status, body, err := cli.Get(context.Background(), nil, "http://hertz.servicecomb.demo/ping", config.WithSD(true)) - if err != nil { - hlog.Fatal(err) - } - hlog.Infof("code=%d,body=%s", status, string(body)) - } -} -``` - -## Configuration - -The configuration of Servicecomb client and server can be customized, refer to the configuration of [go-chassis/sc-client](https://github.com/go-chassis/sc-client). - -## Complete Example - -For more, see [example](https://github.com/hertz-contrib/registry/tree/main/servicecomb/example) . +--- +title: "servicecomb" +date: 2023-04-22 +weight: 7 +keywords: ["Service Registration and Discovery", "servicecomb"] +description: "Service Registration and Discovery servicecomb Extensions provided by Hertz." +--- + +## Install + +```go +go get github.com/hertz-contrib/registry/servicecomb +``` + +## Service Registry + +### Option + +Servicecomb extension provides option configuration in the service registry section. + +#### WithAppId + +Servicecomb extension provides `WithAppId` to help users configure the AppId of Servicecomb. Defaults to "DEFAULT" . + +Function signature: + +```go +func WithAppId(appId string) RegistryOption +``` + +Example: + +```go +func main() { + // ... + r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, + servicecomb.WithAppId("appID"), + ) + if err != nil { + log.Fatal(err) + return + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.servicecomb.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +#### WithRegistryVersionRule + +Servicecomb extension provides `WithRegistryVersionRule` to help users configure the version requirements of Servicecomb. Defaults to 1.0.0 . + +Function signature: + +```go +func WithRegistryVersionRule(versionRule string) RegistryOption +``` + +Example: + +```go +func main() { + // ... + r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, + servicecomb.WithRegistryVersionRule("1.1.0"), + ) + if err != nil { + log.Fatal(err) + return + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.servicecomb.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +#### WithRegistryHostName + +Servicecomb extension provides `WithRegistryHostName` to help users configure Servicecomb's hostname. Defaults to "DEFAULT" . + +Function signature: + +```go +func WithRegistryHostName(hostName string) RegistryOption +``` + +Example: + +```go +func main() { + // ... + r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, + servicecomb.WithRegistryHostName("hostName"), + ) + if err != nil { + log.Fatal(err) + return + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.servicecomb.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +#### WithRegistryHeartbeatInterval + +Servicecomb extension provides `WithRegistryHeartbeatInterval` to help users configure the interval for sending heartbeat packets. Default is 5. + +Function signature: + +```go +func WithRegistryHeartbeatInterval(second int32) RegistryOption +``` + +Example: + +```go +func main() { + // ... + r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, + servicecomb.WithRegistryHeartbeatInterval(10), + ) + if err != nil { + log.Fatal(err) + return + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.servicecomb.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +### NewDefaultSCRegistry + +`NewDefaultSCRegistry` uses service-comb to create a default service registry, which needs to pass in the endpoint value. The service registry configuration can be customized. + +Function signature: + +```go +func NewDefaultSCRegistry(endPoints []string, opts ...RegistryOption) (registry.Registry, error) +``` + +Example: + +```go +func main() { + // ... + r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}) + if err != nil { + log.Fatal(err) + return + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.servicecomb.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +### NewSCRegistry + +`NewSCRegistry` uses service-comb to create a new service registry. It needs to pass in a custom client. Customizable service registry configuration. + +Function signature: + +```go +func NewSCRegistry(client *sc.Client, opts ...RegistryOption) registry.Registry +``` + +Example: + +```go +func main() { + client := &sc.Client{ + // ... + } + // ... + r, err := servicecomb.NewSCRegistry(client) + if err != nil { + log.Fatal(err) + return + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.servicecomb.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +## Service Discovery + +### Option + +Servicecomb extension provides option configuration in the service discovery section. + +#### WithAppId + +Servicecomb extension provides `WithAppId` to help users configure the AppId of Servicecomb. Defaults to "DEFAULT" . + +Function signature: + +```go +func WithResolverAppId(appId string) ResolverOption +``` + +Example: + +```go +func main() { + // ... + r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, + servicecomb.WithAppId("appID"), + ) + if err != nil { + panic(err) + } + cli, err := client.NewClient() + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + // ... +} +``` + +#### WithResolverVersionRule + +Servicecomb extension provides `WithResolverVersionRule` to help users configure Servicecomb's version requirements. Defaults to latest . + +Function signature: + +```go +func WithResolverVersionRule(versionRule string) ResolverOption +``` + +Example: + +```go +func main() { + // ... + r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, + servicecomb.WithResolverVersionRule("1.0.0"), + ) + if err != nil { + panic(err) + } + cli, err := client.NewClient() + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + // ... +} +``` + +#### WithResolverConsumerId + +Servicecomb extension provides `WithResolverConsumerId` to help users configure Servicecomb's ConsumerId . Default is empty . + +Function signature: + +```go +func WithResolverConsumerId(consumerId string) ResolverOption +``` + +Example: + +```go +func main() { + // ... + r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, + servicecomb.WithResolverConsumerId("1"), + ) + if err != nil { + panic(err) + } + cli, err := client.NewClient() + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + // ... +} +``` + +### NewDefaultSCResolver + +`NewDefaultSCResolver` uses service-comb to create a default service discovery center, which needs to pass in the endpoint value. Service discovery center configuration can be customized. + +Function signature: + +```go +func NewDefaultSCResolver(endPoints []string, opts ...ResolverOption) (discovery.Resolver, error) +``` + +Example: + +```go +func main() { + // ... + r, err := servicecomb.NewDefaultSCResolver([]string{scAddr}) + if err != nil { + panic(err) + } + cli, err := client.NewClient() + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + // ... +} +``` + +### NewSCResolver + +`NewSCReslover` uses service-comb to create a new service discovery center. It needs to pass in a custom client. The configuration of the service discovery center can be customized. + +Function signature: + +```go +func NewSCResolver(cli *sc.Client, opts ...ResolverOption) discovery.Resolver +``` + +Example: + +```go +func main() { + client := &sc.Client{ + // ... + } + // ... + r, err := servicecomb.NewSCResolver(client) + if err != nil { + panic(err) + } + cli, err := client.NewClient() + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + // ... +} +``` + +## How to use + +### Server + +```go +import ( + "context" + "log" + "sync" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/protocol/consts" + "github.com/hertz-contrib/registry/servicecomb" +) + +func main() { + const scAddr = "127.0.0.1:30100" + const addr = "127.0.0.1:8701" + r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}) + if err != nil { + log.Fatal(err) + return + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.servicecomb.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + + h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { + ctx.JSON(consts.StatusOK, utils.H{"ping": "pong1"}) + }) + h.Spin() +} +``` + +### Client + +```go +import ( + "context" + + "github.com/cloudwego/hertz/pkg/app/client" + "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" + "github.com/cloudwego/hertz/pkg/common/config" + "github.com/cloudwego/hertz/pkg/common/hlog" + "github.com/hertz-contrib/registry/servicecomb" +) + +func main() { + const scAddr = "127.0.0.1:30100" + // build a servicecomb resolver + r, err := servicecomb.NewDefaultSCResolver([]string{scAddr}) + if err != nil { + panic(err) + } + // build a hertz client with the servicecomb resolver + cli, err := client.NewClient() + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + for i := 0; i < 10; i++ { + status, body, err := cli.Get(context.Background(), nil, "http://hertz.servicecomb.demo/ping", config.WithSD(true)) + if err != nil { + hlog.Fatal(err) + } + hlog.Infof("code=%d,body=%s", status, string(body)) + } +} +``` + +## Configuration + +The configuration of Servicecomb client and server can be customized, refer to the configuration of [go-chassis/sc-client](https://github.com/go-chassis/sc-client). + +## Complete Example + +For more, see [example](https://github.com/hertz-contrib/registry/tree/main/servicecomb/example) . diff --git a/content/en/docs/hertz/tutorials/service-governance/service_discovery/zookeeper.md b/content/en/docs/hertz/tutorials/service-governance/service_discovery/zookeeper.md index b7c9f32e95..ef1dbbeb80 100644 --- a/content/en/docs/hertz/tutorials/service-governance/service_discovery/zookeeper.md +++ b/content/en/docs/hertz/tutorials/service-governance/service_discovery/zookeeper.md @@ -1,213 +1,213 @@ ---- -title: "zookeeper" -date: 2023-04-22 -weight: 8 -keywords: ["Service Registration and Discovery", "zookeeper"] -description: "Service Registration and Discovery zookeeper Extensions provided by Hertz." ---- - -## Install - -```go -go get github.com/hertz-contrib/registry/zookeeper -``` - -## Service Registry - -### NewZookeeperRegistry - -`NewZookeeperRegistry` uses zookeeper to create a service registry. You need to pass the service to `Connect` through a string slice together with the session timeout. - -Function signature: - -```go -func NewZookeeperRegistry(servers []string, sessionTimeout time.Duration) (registry.Registry, error) -``` - -Example: - -```go -func main() { - // ... - r, err := zookeeper.NewZookeeperRegistry([]string{"127.0.0.1:2181"}, 40*time.Second) - if err != nil { - panic(err) - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - // ... -} -``` - -### NewZookeeperRegistryWithAuth - -`NewZookeeperRegistryWithAuth` uses zookeeper to create a service registry. You need to pass the service into `Connect` through a string slice and session timeout time. In addition, you need to pass in the user and password to call `AddAuth`, the user and password Can not be empty. - -Function signature: - -```go -func NewZookeeperRegistryWithAuth(servers []string, sessionTimeout time.Duration, user, password string) -``` - -Example: - -```go -func main() { - // ... - r, err := zookeeper.NewZookeeperRegistryWithAuth([]string{"127.0.0.1:2181"}, 20*time.Second, "hertzuser", "hertzpass") - if err != nil { - panic(err) - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - // ... -} -``` - -## Service Discovery - -### NewZookeeperResolver - -`NewZookeeperResolver` uses zookeeper to create a service discovery center, which needs to pass a string slice and session timeout to `Connect`. - -Function signature: - -```go -func NewZookeeperResolver(servers []string, sessionTimeout time.Duration) (discovery.Resolver, error) -``` - -Example: - -```go -func main() { - cli, err := client.NewClient() - if err != nil { - panic(err) - } - r, err := zookeeper.NewZookeeperResolver([]string{"127.0.0.1:2181"}, 40*time.Second) - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - // ... -} -``` - -### NewZookeeperResolverWithAuth - -`NewZookeeperResolverWithAuth` uses zookeeper to create a service discovery center. You need to pass the service into `Connect` through a string slice and session timeout. In addition, you need to pass in the user and password to call `AddAuth`, the user and password Can not be empty. - -Function signature: - -```go -func NewZookeeperResolverWithAuth(servers []string, sessionTimeout time.Duration, user, password string) -``` - -Example: - -```go -func main() { - cli, err := client.NewClient() - if err != nil { - panic(err) - } - r, err := zookeeper.NewZookeeperResolverWithAuth([]string{"127.0.0.1:2181"}, 40*time.Second, "hertzuser", "hertzpass") - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - // ... -} -``` - -## How to use - -### Server - -```go -import ( - "context" - "time" - - "github.com/cloudwego/hertz/pkg/app" - "github.com/cloudwego/hertz/pkg/app/server" - "github.com/cloudwego/hertz/pkg/app/server/registry" - "github.com/cloudwego/hertz/pkg/common/utils" - "github.com/cloudwego/hertz/pkg/protocol/consts" - "github.com/hertz-contrib/registry/zookeeper" -) - -func main() { - addr := "127.0.0.1:8888" - r, err := zookeeper.NewZookeeperRegistry([]string{"127.0.0.1:2181"}, 40*time.Second) - if err != nil { - panic(err) - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { - ctx.JSON(consts.StatusOK, utils.H{"ping": "pong2"}) - }) - h.Spin() -} -``` - -### Client - -```go -import ( - "context" - "time" - - "github.com/cloudwego/hertz/pkg/app/client" - "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" - "github.com/cloudwego/hertz/pkg/common/config" - "github.com/cloudwego/hertz/pkg/common/hlog" - "github.com/hertz-contrib/registry/zookeeper" -) - -func main() { - cli, err := client.NewClient() - if err != nil { - panic(err) - } - r, err := zookeeper.NewZookeeperResolver([]string{"127.0.0.1:2181"}, 40*time.Second) - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - for i := 0; i < 10; i++ { - status, body, err := cli.Get(context.Background(), nil, "http://hertz.test.demo/ping", config.WithSD(true)) - if err != nil { - hlog.Fatal(err) - } - hlog.Infof("code=%d,body=%s", status, string(body)) - } -} -``` - -## Configuration - -The configuration of Zookeeper client and server can be customized, refer to the configuration of [go-zookeeper/zk](https://github.com/go-zookeeper/zk). - -## Complete Example - -For more, see [example](https://github.com/hertz-contrib/registry/tree/main/zookeeper/example) . +--- +title: "zookeeper" +date: 2023-04-22 +weight: 8 +keywords: ["Service Registration and Discovery", "zookeeper"] +description: "Service Registration and Discovery zookeeper Extensions provided by Hertz." +--- + +## Install + +```go +go get github.com/hertz-contrib/registry/zookeeper +``` + +## Service Registry + +### NewZookeeperRegistry + +`NewZookeeperRegistry` uses zookeeper to create a service registry. You need to pass the service to `Connect` through a string slice together with the session timeout. + +Function signature: + +```go +func NewZookeeperRegistry(servers []string, sessionTimeout time.Duration) (registry.Registry, error) +``` + +Example: + +```go +func main() { + // ... + r, err := zookeeper.NewZookeeperRegistry([]string{"127.0.0.1:2181"}, 40*time.Second) + if err != nil { + panic(err) + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + // ... +} +``` + +### NewZookeeperRegistryWithAuth + +`NewZookeeperRegistryWithAuth` uses zookeeper to create a service registry. You need to pass the service into `Connect` through a string slice and session timeout time. In addition, you need to pass in the user and password to call `AddAuth`, the user and password Can not be empty. + +Function signature: + +```go +func NewZookeeperRegistryWithAuth(servers []string, sessionTimeout time.Duration, user, password string) +``` + +Example: + +```go +func main() { + // ... + r, err := zookeeper.NewZookeeperRegistryWithAuth([]string{"127.0.0.1:2181"}, 20*time.Second, "hertzuser", "hertzpass") + if err != nil { + panic(err) + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + // ... +} +``` + +## Service Discovery + +### NewZookeeperResolver + +`NewZookeeperResolver` uses zookeeper to create a service discovery center, which needs to pass a string slice and session timeout to `Connect`. + +Function signature: + +```go +func NewZookeeperResolver(servers []string, sessionTimeout time.Duration) (discovery.Resolver, error) +``` + +Example: + +```go +func main() { + cli, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := zookeeper.NewZookeeperResolver([]string{"127.0.0.1:2181"}, 40*time.Second) + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + // ... +} +``` + +### NewZookeeperResolverWithAuth + +`NewZookeeperResolverWithAuth` uses zookeeper to create a service discovery center. You need to pass the service into `Connect` through a string slice and session timeout. In addition, you need to pass in the user and password to call `AddAuth`, the user and password Can not be empty. + +Function signature: + +```go +func NewZookeeperResolverWithAuth(servers []string, sessionTimeout time.Duration, user, password string) +``` + +Example: + +```go +func main() { + cli, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := zookeeper.NewZookeeperResolverWithAuth([]string{"127.0.0.1:2181"}, 40*time.Second, "hertzuser", "hertzpass") + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + // ... +} +``` + +## How to use + +### Server + +```go +import ( + "context" + "time" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/protocol/consts" + "github.com/hertz-contrib/registry/zookeeper" +) + +func main() { + addr := "127.0.0.1:8888" + r, err := zookeeper.NewZookeeperRegistry([]string{"127.0.0.1:2181"}, 40*time.Second) + if err != nil { + panic(err) + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { + ctx.JSON(consts.StatusOK, utils.H{"ping": "pong2"}) + }) + h.Spin() +} +``` + +### Client + +```go +import ( + "context" + "time" + + "github.com/cloudwego/hertz/pkg/app/client" + "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" + "github.com/cloudwego/hertz/pkg/common/config" + "github.com/cloudwego/hertz/pkg/common/hlog" + "github.com/hertz-contrib/registry/zookeeper" +) + +func main() { + cli, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := zookeeper.NewZookeeperResolver([]string{"127.0.0.1:2181"}, 40*time.Second) + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + for i := 0; i < 10; i++ { + status, body, err := cli.Get(context.Background(), nil, "http://hertz.test.demo/ping", config.WithSD(true)) + if err != nil { + hlog.Fatal(err) + } + hlog.Infof("code=%d,body=%s", status, string(body)) + } +} +``` + +## Configuration + +The configuration of Zookeeper client and server can be customized, refer to the configuration of [go-zookeeper/zk](https://github.com/go-zookeeper/zk). + +## Complete Example + +For more, see [example](https://github.com/hertz-contrib/registry/tree/main/zookeeper/example) . diff --git a/content/en/docs/hertz/tutorials/service-migration/_index.md b/content/en/docs/hertz/tutorials/service-migration/_index.md index 5e3a3c4902..73a32eb481 100644 --- a/content/en/docs/hertz/tutorials/service-migration/_index.md +++ b/content/en/docs/hertz/tutorials/service-migration/_index.md @@ -3,7 +3,6 @@ title: "Migration to Hertz" weight: 7 keywords: ["Migration to Hertz"] description: "Hertz provides the ability to migrate from other frameworks (FastHTTP, Gin) to Hertz." - --- ## Migration Script diff --git a/content/en/docs/hertz/tutorials/toolkit/_index.md b/content/en/docs/hertz/tutorials/toolkit/_index.md index 0453eb0e68..1658ab7f40 100644 --- a/content/en/docs/hertz/tutorials/toolkit/_index.md +++ b/content/en/docs/hertz/tutorials/toolkit/_index.md @@ -3,5 +3,4 @@ title: "hz Code Generation" weight: 6 keywords: ["hz Code Generation"] description: "The code generation tool hz provided by Hertz." - --- diff --git a/content/en/docs/hertz/tutorials/toolkit/annotation.md b/content/en/docs/hertz/tutorials/toolkit/annotation.md index 2c31e4d0c1..9029ccdea6 100644 --- a/content/en/docs/hertz/tutorials/toolkit/annotation.md +++ b/content/en/docs/hertz/tutorials/toolkit/annotation.md @@ -1,8 +1,9 @@ --- -title: 'hz annotation' +title: "hz annotation" date: 2023-02-21 weight: 6 -keywords: [ "hz annotation", "api annotation", "Field annotation", "Method annotation" ] +keywords: + ["hz annotation", "api annotation", "Field annotation", "Method annotation"] description: "The IDL annotation provided by hz." --- @@ -10,7 +11,7 @@ description: "The IDL annotation provided by hz." > Field annotation can be used > -for [parameter binding and validation](/docs/hertz/tutorials/basic-feature/binding-and-validate/) +> for [parameter binding and validation](/docs/hertz/tutorials/basic-feature/binding-and-validate/) > > Method annotation can be used to generate code that related to route registration @@ -22,7 +23,7 @@ Field annotation tag description can be referenced [supported-tags](/docs/hertz/tutorials/basic-feature/binding-and-validate/#supported-tags). | _Field annotation_ | | -|------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------| +| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | | annotation | description | | api.raw_body | generate "raw_body" tag | | api.query | generate "query" tag | @@ -36,7 +37,7 @@ referenced [supported-tags](/docs/hertz/tutorials/basic-feature/binding-and-vali | api.none | Generate "-" tag, please refer to [api.none annotation usage](/docs/hertz/tutorials/toolkit/more-feature/api_none/) for details | | _Method annotation_ | | -|---------------------|-----------------------------------| +| ------------------- | --------------------------------- | | annotation | description | | api.get | define GET methods and routes | | api.post | define POST methods and routes | @@ -52,7 +53,7 @@ referenced [supported-tags](/docs/hertz/tutorials/basic-feature/binding-and-vali In addition to the annotations provided by [hz](#hz), one additional annotation has been added for client scenarios. | _Client annotation_ | | -|---------------------|-------------------------------------------| +| ------------------- | ----------------------------------------- | | annotation | description | | api.base_domain | specify the default access request domain | diff --git a/content/en/docs/hertz/tutorials/toolkit/cautions.md b/content/en/docs/hertz/tutorials/toolkit/cautions.md index 25c6941659..50abb339d8 100644 --- a/content/en/docs/hertz/tutorials/toolkit/cautions.md +++ b/content/en/docs/hertz/tutorials/toolkit/cautions.md @@ -1,10 +1,11 @@ --- -title: 'note' +title: "note" date: 2023-02-21 weight: 8 keywords: ["note", "protobuf", "thrift"] description: "Precautions when using hz." --- + ## Location of biz layer code generation when using protobuf IDL hz currently supports the syntax of [proto2](https://developers.google.com/protocol-buffers/docs/proto) / [proto3](https://developers.google.com/protocol-buffers/docs/proto3). @@ -21,7 +22,7 @@ Assuming the current project is (module=github.com/a/b): - go_package="github.com/a/b/biz/model/c/d": Model will be generated under "/biz/model/c/d", where "biz/model" is the default model generation path and can be modified using the "--model_dir" option; - go_package="x/y/z": Generate code under "biz/model/x/y/z" (relative path completion); - go_package="biz/model/c/d": Generate code under "biz/model/biz/model/c/d". - + **It is recommended that users define "go_package" such as "{$MODULE}/{$MODEL_DIR}/x/y/z" (where {$MODEL_DIR} defaults to "biz/model", and users can also use the "model_dir" option to define it).** ### The location of the handler file @@ -66,52 +67,52 @@ The router registration file will also take namespace as the generation path, an 1. Notes on using custom path - For the convenience of user, hz provides custom handler paths, model paths, templates, etc. However, hz does not save the current project information when creating a new project, so it can be considered as a stateless update when using the update command. Therefore, for the same set of IDL in new and update, using different custom information may result in duplicate code, for example, as follows: + For the convenience of user, hz provides custom handler paths, model paths, templates, etc. However, hz does not save the current project information when creating a new project, so it can be considered as a stateless update when using the update command. Therefore, for the same set of IDL in new and update, using different custom information may result in duplicate code, for example, as follows: - Create a new project: + Create a new project: - ```bash - hz new -idl demo.thrift + ```bash + hz new -idl demo.thrift - // In this case, hz will generate the model under "biz/model" - ``` + // In this case, hz will generate the model under "biz/model" + ``` - Update an existing project: + Update an existing project: - ```bash - hz update -idl demo.thrift --model_dir=my_model + ```bash + hz update -idl demo.thrift --model_dir=my_model - // In this case, hz will not update the model code under "biz/model", but under "my_model"; then the code under "biz/model" and "my_model" will be duplicated, and the new handler will depend on "my_model",while the previous handler will depend on "biz/model". In this case, you need to delete & change some code manually. - ``` + // In this case, hz will not update the model code under "biz/model", but under "my_model"; then the code under "biz/model" and "my_model" will be duplicated, and the new handler will depend on "my_model",while the previous handler will depend on "biz/model". In this case, you need to delete & change some code manually. + ``` - Therefore, **we hope that user use the update command with custom paths "client_dir", "model_dir", "handler_dir", preferably same as new.** + Therefore, **we hope that user use the update command with custom paths "client_dir", "model_dir", "handler_dir", preferably same as new.** 2. Behavior of update handler - hz will generate handlers based on default/custom template when creating a new project, where each service generates a file that contains all the handler code defined by the service; if IDL defines multiple services, each service will generate a file, and these files are in the same path; for example: + hz will generate handlers based on default/custom template when creating a new project, where each service generates a file that contains all the handler code defined by the service; if IDL defines multiple services, each service will generate a file, and these files are in the same path; for example: - ```thrift - // demo.thrift - namespace go hello.example + ```thrift + // demo.thrift + namespace go hello.example - service Service1 { - HelloResp Method1(1: HelloReq request) (api.get="/hello"); - } + service Service1 { + HelloResp Method1(1: HelloReq request) (api.get="/hello"); + } - service Service2 { - HelloResp Method2(1: HelloReq request) (api.get="/new"); - } + service Service2 { + HelloResp Method2(1: HelloReq request) (api.get="/new"); + } - // Then the handler file generated by the IDL is as follows: - ${handler_dir}/${namespace}/service1.go -> method1 - ${handler_dir}/${namespace}/service2.go -> method2 - ``` + // Then the handler file generated by the IDL is as follows: + ${handler_dir}/${namespace}/service1.go -> method1 + ${handler_dir}/${namespace}/service2.go -> method2 + ``` - **When a new method is added to the IDL, the handler template will be added at the end of the corresponding service file; note that the handler added here will use the default template, and the new service file will use a custom template if appropriate.** + **When a new method is added to the IDL, the handler template will be added at the end of the corresponding service file; note that the handler added here will use the default template, and the new service file will use a custom template if appropriate.** 3. Behavior of update router - The router code generated by hz in new mainly includes the following three: + The router code generated by hz in new mainly includes the following three: - biz/router/${namespace}/${idlName}.go: Each primary IDL generates a corresponding routing registration code file, which registers all the routes defined in the IDL in a routing group, and sets the default middleware. @@ -123,7 +124,7 @@ The router registration file will also take namespace as the generation path, an - biz/router/register.go: This file is responsible for calling the route registration generated by different IDL; for example, if i define service in both IDL "demo1.thrift" and "demo2.thrift", then both files will generate the corresponding route registration code. register.go is responsible for calling the route registration functions of these two parts. - Based on the above description, a description of the router's behavior during update is given: + Based on the above description, a description of the router's behavior during update is given: - biz/${namespace}/${idlName}.go: Regenerate based on IDL every time, users should not change the code of this file, otherwise the code will be lost. diff --git a/content/en/docs/hertz/tutorials/toolkit/command.md b/content/en/docs/hertz/tutorials/toolkit/command.md index a35e6906a8..fcf0b7d933 100644 --- a/content/en/docs/hertz/tutorials/toolkit/command.md +++ b/content/en/docs/hertz/tutorials/toolkit/command.md @@ -1,10 +1,11 @@ --- -title: 'hz commands' +title: "hz commands" date: 2023-02-21 weight: 7 keywords: ["hz commands", "New", "Update", "Model", "Client"] description: "hz commands." --- + ## Command line parameter description #### Global @@ -38,7 +39,7 @@ GLOBAL OPTIONS: - update: Updating an existing Hertz project - + - model: Generate only model code @@ -58,7 +59,7 @@ USAGE: hz new [command options] [arguments...] OPTIONS: - --idl value [ --idl value ] Specify the IDL file path. (.thrift or .proto) + --idl value [ --idl value ] Specify the IDL file path. (.thrift or .proto) --service value Specify the service name. --module value, --mod value Specify the Go module name. --out_dir value Specify the project path. @@ -71,9 +72,9 @@ OPTIONS: --thriftgo value, -t value [ --thriftgo value, -t value ] Specify arguments for the thriftgo. ({flag}={value}) --protoc value, -p value [ --protoc value, -p value ] Specify arguments for the protoc. ({flag}={value}) --option_package value, -P value [ --option_package value, -P value ] Specify the package path. ({include_path}={import_path}) - --no_recurse Generate master model only. (default: false) + --no_recurse Generate master model only. (default: false) --force, -f Force new a project, which will overwrite the generated files (default: false) - --enable_extends Parse 'extends' for thrift IDL (default: false) + --enable_extends Parse 'extends' for thrift IDL (default: false) --json_enumstr Use string instead of num for json enums when idl is thrift. (default: false) --unset_omitempty Remove 'omitempty' tag for generated struct. (default: false) --pb_camel_json_tag Convert Name style for json tag to camel(Only works protobuf). (default: false) @@ -221,7 +222,7 @@ OPTIONS: --model_dir value Specify the model relative path (based on "out_dir"). --client_dir value Specify the client path. If not specified, IDL generated path is used for 'client' command; no client code is generated for 'new' command --use value Specify the model package to import for handler. - --proto_path value, -I value [ --proto_path value, -I value ] Add an IDL search path for includes. (Valid only if idl is protobuf) + --proto_path value, -I value [ --proto_path value, -I value ] Add an IDL search path for includes. (Valid only if idl is protobuf) --thriftgo value, -t value [ --thriftgo value, -t value ] Specify arguments for the thriftgo. ({flag}={value}) --protoc value, -p value [ --protoc value, -p value ] Specify arguments for the protoc. ({flag}={value}) --option_package value, -P value [ --option_package value, -P value ] Specify the package path. ({include_path}={import_path}) @@ -235,7 +236,7 @@ OPTIONS: --exclude_file value, -E value [ --exclude_file value, -E value ] Specify the files that do not need to be updated. --customize_package value Specify the path for package template. --handler_by_method Generate a separate handler file for each method. (default: false) - --protoc-plugins value [ --protoc-plugins value ] Specify plugins for the protoc. ({plugin_name}:{options}:{out_dir}) + --protoc-plugins value [ --protoc-plugins value ] Specify plugins for the protoc. ({plugin_name}:{options}:{out_dir}) --thrift-plugins value [ --thrift-plugins value ] Specify plugins for the thriftgo. ({plugin_name}:{options}) --help, -h show help (default: false) ``` @@ -260,7 +261,7 @@ OPTIONS: -- client_dir: Specify the path for generating client-side code. If not specified, it will not be generated; Currently, a global client is generated for each service. To generate more comprehensive client-side code, please use [hz client](/docs/hertz/tutorials/toolkit/more-feature/client/) command. Note: If updating the same set of idls, the value of client_dir needs to be the same as when using new, otherwise redundant code will be generated and the user needs to delete it themselves. +- client_dir: Specify the path for generating client-side code. If not specified, it will not be generated; Currently, a global client is generated for each service. To generate more comprehensive client-side code, please use [hz client](/docs/hertz/tutorials/toolkit/more-feature/client/) command. Note: If updating the same set of idls, the value of client_dir needs to be the same as when using new, otherwise redundant code will be generated and the user needs to delete it themselves. @@ -353,7 +354,7 @@ OPTIONS: --thriftgo value, -t value [ --thriftgo value, -t value ] Specify arguments for the thriftgo. ({flag}={value}) --protoc value, -p value [ --protoc value, -p value ] Specify arguments for the protoc. ({flag}={value}) --no_recurse Generate master model only. (default: false) - --json_enumstr Use string instead of num for json enums when idl is thrift. (default: false) + --json_enumstr Use string instead of num for json enums when idl is thrift. (default: false) --unset_omitempty Remove 'omitempty' tag for generated struct. (default: false) --pb_camel_json_tag Convert Name style for json tag to camel(Only works protobuf). (default: false) --snake_tag Use snake_case style naming for tags. (Only works for 'form', 'query', 'json') (default: false) @@ -445,7 +446,7 @@ OPTIONS: --protoc value, -p value [ --protoc value, -p value ] Specify arguments for the protoc. ({flag}={value}) --no_recurse Generate master model only. (default: false) --enable_extends Parse 'extends' for thrift IDL (default: false) - --json_enumstr Use string instead of num for json enums when idl is thrift. (default: false) + --json_enumstr Use string instead of num for json enums when idl is thrift. (default: false) --unset_omitempty Remove 'omitempty' tag for generated struct. (default: false) --pb_camel_json_tag Convert Name style for json tag to camel(Only works protobuf). (default: false) --snake_tag Use snake_case style naming for tags. (Only works for 'form', 'query', 'json') (default: false) diff --git a/content/en/docs/hertz/tutorials/toolkit/install.md b/content/en/docs/hertz/tutorials/toolkit/install.md index 348bb22f6b..88f96c3add 100644 --- a/content/en/docs/hertz/tutorials/toolkit/install.md +++ b/content/en/docs/hertz/tutorials/toolkit/install.md @@ -1,10 +1,11 @@ --- -title: 'hz install' +title: "hz install" date: 2023-02-21 weight: 1 keywords: ["hz install"] description: "hz install." --- + hz is a tool provided by the Hertz framework for generating code. Currently, hz can generate scaffolding for Hertz projects based on thrift and protobuf's IDL. ## Install @@ -12,15 +13,15 @@ hz is a tool provided by the Hertz framework for generating code. Currently, hz 1. Make sure the `GOPATH` environment variable has been defined correctly (eg `export GOPATH=~/go`) and add `$GOPATH/bin` to the PATH environment (eg `export PATH=$GOPATH/bin:$PATH`); do not set `GOPATH` to a directory that the current user does not have read/write access to. 2. Install hz: - ```bash - go install github.com/cloudwego/hertz/cmd/hz@latest - ``` + ```bash + go install github.com/cloudwego/hertz/cmd/hz@latest + ``` 3. Verify that the installation was successful `hz -v`, if the following version message is displayed, the installation was successful - ```console - hz version v0.x.x - ``` + ```console + hz version v0.x.x + ``` **Note**,Since hz creates soft links to its own binary, make sure that the installation path of hz has writable permissions. diff --git a/content/en/docs/hertz/tutorials/toolkit/layout.md b/content/en/docs/hertz/tutorials/toolkit/layout.md index 3a3c7b2924..b9ce11b453 100644 --- a/content/en/docs/hertz/tutorials/toolkit/layout.md +++ b/content/en/docs/hertz/tutorials/toolkit/layout.md @@ -38,7 +38,7 @@ The structure of the code generated by hz is similar. Below, we will use the thr └── router_gen.go // the route registration code generated by hz, for calling user-defined routes and routes generated by hz ├── .hz // create code flags for hz without modification ├── build.sh // program compilation script, default not generated under Windows, you can directly use the go build command to compile the program -├── script +├── script │ └── bootstrap.sh // program running script, default not generated under Windows, you can directly run main.go └── .gitignore ``` @@ -47,7 +47,7 @@ The structure of the code generated by hz is similar. Below, we will use the thr ``` . -├── biz // business layer, which stores business logic +├── biz // business layer, which stores business logic │ └── model // IDL content-related generation code │ └── hello // hello/example corresponds to the namespace defined in thrift IDL; for protobuf IDL, it corresponds to the last level of go_package │ └── example diff --git a/content/en/docs/hertz/tutorials/toolkit/more-feature/_index.md b/content/en/docs/hertz/tutorials/toolkit/more-feature/_index.md index b8f16e79ae..a6a4ba02fa 100644 --- a/content/en/docs/hertz/tutorials/toolkit/more-feature/_index.md +++ b/content/en/docs/hertz/tutorials/toolkit/more-feature/_index.md @@ -1,6 +1,7 @@ --- title: "more features" weight: 9 -keywords: ["more features", "custom template", "plugin", "hz client", "api.none"] +keywords: + ["more features", "custom template", "plugin", "hz client", "api.none"] description: "More features provided by hz." --- diff --git a/content/en/docs/hertz/tutorials/toolkit/more-feature/api_none.md b/content/en/docs/hertz/tutorials/toolkit/more-feature/api_none.md index 8fa71881c2..be065dc888 100644 --- a/content/en/docs/hertz/tutorials/toolkit/more-feature/api_none.md +++ b/content/en/docs/hertz/tutorials/toolkit/more-feature/api_none.md @@ -1,10 +1,11 @@ --- -title: 'api.none annotation usage' +title: "api.none annotation usage" date: 2023-04-23 weight: 5 keywords: ["api.none", "thrift", "protobuf"] description: "Description of the api.none annotation provided by hz." --- + ## Introduction The code generated by hz automatically adds a go tag to the `struct`, thus facilitating parameter binding. diff --git a/content/en/docs/hertz/tutorials/toolkit/more-feature/client.md b/content/en/docs/hertz/tutorials/toolkit/more-feature/client.md index a65b82482a..b8117832dc 100644 --- a/content/en/docs/hertz/tutorials/toolkit/more-feature/client.md +++ b/content/en/docs/hertz/tutorials/toolkit/more-feature/client.md @@ -1,5 +1,5 @@ --- -title: 'hz client code generation' +title: "hz client code generation" date: 2023-02-20 weight: 4 keywords: ["hz client", "Advanced Settings"] @@ -24,10 +24,10 @@ This example is based on thrift, and protoc is similar to it. ### Define IDL ->The definition and semantics of the IDL are exactly the same as the current definition, so it is basically possible to generate client code without modifying the original IDL. +> The definition and semantics of the IDL are exactly the same as the current definition, so it is basically possible to generate client code without modifying the original IDL. ->But for the client scenario, one annotation has been added, ->api.base_domain: specifies the default request domain to access. +> But for the client scenario, one annotation has been added, +> api.base_domain: specifies the default request domain to access. **Warn**: When the `api.any` annotation is used, the client automatically generates client code for the `post` method to replace `any`. @@ -77,18 +77,17 @@ hz client --mod=a/b/c --idl=../idl/psm.thrift --model_dir=model --client_dir=her ### Client Option -> > Take the code generated by thrift IDL as an example - ```go +```go func main() { - generatedClient, err := hello_service.NewHelloServiceClient("https://www.example.com"), + generatedClient, err := hello_service.NewHelloServiceClient("https://www.example.com"), hello_service.WithHertzClientOption() // Specify client configuration } ``` ### Request-level configuration -> + > Take the code generated by thrift IDL as an example ```go @@ -111,20 +110,20 @@ func main() { ``` ### Set client middleware -> + > Take the code generated by thrift IDL as an example ```go func main() { generatedClient, err := hello_service.NewHelloServiceClient( - "http://toutiao.hertz.testa", + "http://toutiao.hertz.testa", hello_service.WithHertzClientMiddleware(), // Specify the client's middleware ) } ``` ### Set global header -> + > Take the code generated by thrift IDL as an example There are some generic header that may need to be carried in every request, or some header that cannot be defined in IDL, then we can inject these header with "WithHeader" so that every request sent will carry these header. @@ -133,20 +132,20 @@ There are some generic header that may need to be carried in every request, or s func main() { generatedClient, err := hello_service.NewHelloServiceClient( "http://toutiao.hertz.testa", - hello_service.WithHeader(), // Specify the header that needs to be carried for each request sent + hello_service.WithHeader(), // Specify the header that needs to be carried for each request sent ) } ``` ### Configure TLS -> + > Take the code generated by thrift IDL as an example Hertz client's TLS goes through the standard network library, so you need to configure it for the standard network library when using the generated one-click calls. ```go func main() { - generatedClient, err := hello_service.NewHelloServiceClient("https://www.example.com"), + generatedClient, err := hello_service.NewHelloServiceClient("https://www.example.com"), hello_service.WithHertzClientOption( client.WithDialer(standard.NewDialer()), // Use of standard libraries client.WithTLSConfig(clientCfg), // TLS Configuration @@ -155,12 +154,12 @@ func main() { ``` ### Custom hertz client -> + > Take the code generated by thrift IDL as an example - ```go +```go func main() { - generatedClient, err := hello_service.NewHelloServiceClient("https://www.example.com"), + generatedClient, err := hello_service.NewHelloServiceClient("https://www.example.com"), hello_service.WithHertzClient() // Specify custom hertz client } ``` diff --git a/content/en/docs/hertz/tutorials/toolkit/more-feature/plugin.md b/content/en/docs/hertz/tutorials/toolkit/more-feature/plugin.md index 43ea939414..bc2ee0f976 100644 --- a/content/en/docs/hertz/tutorials/toolkit/more-feature/plugin.md +++ b/content/en/docs/hertz/tutorials/toolkit/more-feature/plugin.md @@ -1,5 +1,5 @@ --- -title: 'hz access plugin' +title: "hz access plugin" date: 2023-01-21 weight: 3 keywords: ["plugin", "ThriftGo", "Protoc", "go_package"] diff --git a/content/en/docs/hertz/tutorials/toolkit/more-feature/template.md b/content/en/docs/hertz/tutorials/toolkit/more-feature/template.md index b352ec7a43..976570011a 100644 --- a/content/en/docs/hertz/tutorials/toolkit/more-feature/template.md +++ b/content/en/docs/hertz/tutorials/toolkit/more-feature/template.md @@ -15,14 +15,14 @@ Taking the code structure in [The structure of the generated code](/docs/hertz/t ``` . -├── biz +├── biz │ ├── handler // biz/handler is the default handler_dir, which can be modified through --handler_dir │ │ ├── hello // handler related code, related to idl, package template generation │ │ │ └── example -│ │ │ └── hello_service.go +│ │ │ └── hello_service.go │ │ └── ping.go // layout template generation │ ├── model // biz/model is the default model_dir, which can be modified through --model_dir -│ │ └── hello +│ │ └── hello │ │ └── example │ │ └── hello.go // generated by hz calling thriftgo, without involving layout and package templates │ │ └── hello_service // call the hz client command to obtain, related to idl, package template generation @@ -31,16 +31,16 @@ Taking the code structure in [The structure of the generated code](/docs/hertz/t │ └── router // biz/router is the default router_dir, which can be modified through --router_dir │ ├── hello // router related code, related to idl, package template generation │ │ └── example -│ │ ├── hello.go -│ │ └── middleware.go +│ │ ├── hello.go +│ │ └── middleware.go │ └── register.go // when idl is not specified, it is generated by the layout template; when specifying idl, generated by the package template ├── go.mod // go.mod file, layout template generation ├── main.go // program entry, layout template generation ├── router.go // user defined routing methods other than idl, layout template generation └── router_gen.go // route registration code generated by hz, used to call user-defined routes and routes generated by hz, generated by layout templates -├── .hz +├── .hz ├── build.sh // program compilation script, layout template generation -├── script +├── script │ └── bootstrap.sh // program running script, layout template generation └── .gitignore // layout template generation ``` @@ -84,7 +84,7 @@ layouts: delims: - "" - "" - body: "" + body: "" # project main.go file - path: main.go delims: @@ -238,7 +238,7 @@ layouts: CURDIR=$(cd $(dirname $0); pwd) BinaryName={{.ServiceName}} echo "$CURDIR/bin/${BinaryName}" - exec $CURDIR/bin/${BinaryName} + exec $CURDIR/bin/${BinaryName} ``` ### Template rendering parameter file @@ -249,19 +249,19 @@ Global rendering parameters can be used in various files, and file rendering par #### Global rendering parameters -The key for global rendering parameters is "*", and hz provides the following five global rendering parameters by default: +The key for global rendering parameters is "\*", and hz provides the following five global rendering parameters by default: -| rendering parameter name | default | description | -| :---- | :---- | :---- | -| GoModule | - | go module, can be specified through --module | -| ServiceName | hertz_service | service name, which can be specified through --service | -| UseApacheThrift | - | true when idl is thrift, otherwise false | -| HandlerPkg | handler | the last level path of the handler_dir, can be modified through --handler_dir | -| RouterPkg | router | the last level path of the router_dir, can be modified through --router_dir | +| rendering parameter name | default | description | +| :----------------------- | :------------ | :---------------------------------------------------------------------------- | +| GoModule | - | go module, can be specified through --module | +| ServiceName | hertz_service | service name, which can be specified through --service | +| UseApacheThrift | - | true when idl is thrift, otherwise false | +| HandlerPkg | handler | the last level path of the handler_dir, can be modified through --handler_dir | +| RouterPkg | router | the last level path of the router_dir, can be modified through --router_dir | > Note: Except for UseApacheThrift, all other parameters can be specified through the command line. If this parameter is also specified in the custom rendering parameter file, ensure that the values of the two parameters are consistent, otherwise problems may occur. Therefore, we suggest that when using custom templates, ServiceName, HandlerPkg, and RouterPkg do not need to be specified on the command line, but can be specified in the rendering parameter file. When specifying go mod outside of GOPATH, consistency between the two should be ensured. -Users can customize global rendering parameter names and values according to their needs, but ensure that the key is "*". +Users can customize global rendering parameter names and values according to their needs, but ensure that the key is "\*". #### File rendering parameters @@ -326,8 +326,8 @@ layouts: # go.mod file, requires template rendering data {{.GoModule}} to generate - path: go.mod delims: - - '{{' - - '}}' + - "{{" + - "}}" body: |- module {{.GoModule}} {{- if .UseApacheThrift}} @@ -387,8 +387,8 @@ layouts: # path only indicates the template of handler.go, the specific handler path is determined by the default path and handler_dir - path: handler.go delims: - - '{{' - - '}}' + - "{{" + - "}}" body: |- // Code generated by hertz generator. @@ -425,8 +425,8 @@ layouts: # path only indicates the router.go template, the specific path is determined by the default path and router_dir - path: router.go delims: - - '{{' - - '}}' + - "{{" + - "}}" body: |- // Code generated by hertz generator. DO NOT EDIT. @@ -498,8 +498,8 @@ layouts: # path only indicates the template of middleware.go, the path to middleware is the same as router.go - path: middleware.go delims: - - '{{' - - '}}' + - "{{" + - "}}" body: |- // Code generated by hertz generator. @@ -521,8 +521,8 @@ layouts: # path only indicates the template of client.go, generated only when using hz new --client_dir or hz update --client_dir, path determined by out_dir and client_dir - path: client.go delims: - - '{{' - - '}}' + - "{{" + - "}}" body: |- // Code generated by hertz generator. @@ -550,8 +550,8 @@ layouts: # handler_single means a separate handler template, used to update each new handler when updating - path: handler_single.go delims: - - '{{' - - '}}' + - "{{" + - "}}" body: |+ {{.Comment}} func {{.Name}}(ctx context.Context, c *app.RequestContext) { @@ -572,8 +572,8 @@ layouts: # middleware_single means a separate middleware template, which is used to update each new middleware_single when updating - path: middleware_single.go delims: - - '{{' - - '}}' + - "{{" + - "}}" body: |+ func {{.MiddleWare}}Mw() []app.HandlerFunc { // your code... @@ -582,13 +582,13 @@ layouts: # hertz_client is generated by the hz client command. For detailed code, please refer to https://github.com/cloudwego/hertz/blob/develop/cmd/hz/generator/package_tpl.go#L271 - path: hertz_client.go delims: - - '{{' - - '}}' + - "{{" + - "}}" # idl_client is generated by the hz client command. For detailed code, please refer to https://github.com/cloudwego/hertz/blob/develop/cmd/hz/generator/package_tpl.go#L862 - path: idl_client.go delims: - - '{{' - - '}}' + - "{{" + - "}}" ``` ### Template rendering parameters @@ -601,15 +601,15 @@ Below is an introduction to the template rendering parameters provided by hz by ```go type FilePathRenderInfo struct { - MasterIDLName string // master IDL name - GenPackage string // master IDL generate code package - HandlerDir string // handler generate dir - ModelDir string // model generate dir - RouterDir string // router generate dir - ProjectDir string // projectDir - GoModule string // go module - ServiceName string // service name, changed as services are traversed - MethodName string // method name, changed as methods are traversed + MasterIDLName string // master IDL name + GenPackage string // master IDL generate code package + HandlerDir string // handler generate dir + ModelDir string // model generate dir + RouterDir string // router generate dir + ProjectDir string // projectDir + GoModule string // go module + ServiceName string // service name, changed as services are traversed + MethodName string // method name, changed as methods are traversed HandlerGenPath string // "api.handler_path" value } ``` @@ -633,7 +633,7 @@ type CustomizedFileForMethod struct { FilePackage string // When the method file is generated in a loop, the go package name of the file ServiceInfo *Service // The information defined by the service to which the method belongs } - + type HttpMethod struct { Name string HTTPMethod string @@ -653,7 +653,7 @@ type HttpMethod struct { type CustomizedFileForService struct { *Service // specific information about the service, including the service name, information about the method defined in the servide, etc. FilePath string // When the service file is generated in a loop, the path to the file - FilePackage string // When the service file is looped, the go package name of the file + FilePackage string // When the service file is looped, the go package name of the file IDLPackageInfo *IDLPackageRenderInfo // Information about the IDL definition to which the service belongs } @@ -661,7 +661,7 @@ type Service struct { Name string Methods []*HttpMethod ClientMethods []*ClientMethod - Models []*model.Model // all dependency models + Models []*model.Model // all dependency models BaseDomain string // base domain for client code } ``` @@ -721,7 +721,7 @@ Template format: A simple example of a custom handler template is given below: #### example -> + > example: https://github.com/cloudwego/hertz-examples/tree/main/hz/template - Modify the content of the default handler @@ -730,130 +730,130 @@ A simple example of a custom handler template is given below: ```yaml layouts: - - path: handler.go - body: |- + - path: handler.go + body: |- + {{$OutDirs := GetUniqueHandlerOutDir .Methods}} + package {{.PackageName}} + import ( + "context" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/protocol/consts" + {{- range $k, $v := .Imports}} + {{$k}} "{{$v.Package}}" + {{- end}} + {{- range $_, $OutDir := $OutDirs}} + {{if eq $OutDir "" -}} + "{{$.ProjPackage}}/biz/service" + {{- else -}} + "{{$.ProjPackage}}/biz/service/{{$OutDir}}" + {{- end -}} + {{- end}} + "{{$.ProjPackage}}/biz/utils" + ) + {{range $_, $MethodInfo := .Methods}} + {{$MethodInfo.Comment}} + func {{$MethodInfo.Name}}(ctx context.Context, c *app.RequestContext) { + var err error + {{if ne $MethodInfo.RequestTypeName "" -}} + var req {{$MethodInfo.RequestTypeName}} + err = c.BindAndValidate(&req) + if err != nil { + utils.SendErrResponse(ctx, c, consts.StatusOK, err) + return + } + {{end}} + {{if eq $MethodInfo.OutputDir "" -}} + resp,err := service.New{{$MethodInfo.Name}}Service(ctx, c).Run(&req) + if err != nil { + utils.SendErrResponse(ctx, c, consts.StatusOK, err) + return + } + {{else}} + resp,err := {{$MethodInfo.OutputDir}}.New{{$MethodInfo.Name}}Service(ctx, c).Run(&req) + if err != nil { + utils.SendErrResponse(ctx, c, consts.StatusOK, err) + return + } + {{end}} + utils.SendSuccessResponse(ctx, c, consts.StatusOK, resp) + } + {{end}} + update_behavior: + import_tpl: + - |- {{$OutDirs := GetUniqueHandlerOutDir .Methods}} - package {{.PackageName}} - import ( - "context" - - "github.com/cloudwego/hertz/pkg/app" - "github.com/cloudwego/hertz/pkg/protocol/consts" - {{- range $k, $v := .Imports}} - {{$k}} "{{$v.Package}}" - {{- end}} {{- range $_, $OutDir := $OutDirs}} {{if eq $OutDir "" -}} "{{$.ProjPackage}}/biz/service" {{- else -}} "{{$.ProjPackage}}/biz/service/{{$OutDir}}" - {{- end -}} - {{- end}} - "{{$.ProjPackage}}/biz/utils" - ) - {{range $_, $MethodInfo := .Methods}} - {{$MethodInfo.Comment}} - func {{$MethodInfo.Name}}(ctx context.Context, c *app.RequestContext) { - var err error - {{if ne $MethodInfo.RequestTypeName "" -}} - var req {{$MethodInfo.RequestTypeName}} - err = c.BindAndValidate(&req) - if err != nil { - utils.SendErrResponse(ctx, c, consts.StatusOK, err) - return - } - {{end}} - {{if eq $MethodInfo.OutputDir "" -}} - resp,err := service.New{{$MethodInfo.Name}}Service(ctx, c).Run(&req) - if err != nil { - utils.SendErrResponse(ctx, c, consts.StatusOK, err) - return - } - {{else}} - resp,err := {{$MethodInfo.OutputDir}}.New{{$MethodInfo.Name}}Service(ctx, c).Run(&req) - if err != nil { - utils.SendErrResponse(ctx, c, consts.StatusOK, err) - return - } {{end}} - utils.SendSuccessResponse(ctx, c, consts.StatusOK, resp) - } - {{end}} - update_behavior: - import_tpl: - - |- - {{$OutDirs := GetUniqueHandlerOutDir .Methods}} - {{- range $_, $OutDir := $OutDirs}} - {{if eq $OutDir "" -}} - "{{$.ProjPackage}}/biz/service" - {{- else -}} - "{{$.ProjPackage}}/biz/service/{{$OutDir}}" - {{end}} - {{- end}} - - - path: handler_single.go - body: |+ - {{.Comment}} - func {{.Name}}(ctx context.Context, c *app.RequestContext) { - var err error - {{if ne .RequestTypeName "" -}} - var req {{.RequestTypeName}} - err = c.BindAndValidate(&req) - if err != nil { + {{- end}} + + - path: handler_single.go + body: |+ + {{.Comment}} + func {{.Name}}(ctx context.Context, c *app.RequestContext) { + var err error + {{if ne .RequestTypeName "" -}} + var req {{.RequestTypeName}} + err = c.BindAndValidate(&req) + if err != nil { + utils.SendErrResponse(ctx, c, consts.StatusOK, err) + return + } + {{end}} + {{if eq .OutputDir "" -}} + resp,err := service.New{{.Name}}Service(ctx, c).Run(&req) + {{else}} + resp,err := {{.OutputDir}}.New{{.Name}}Service(ctx, c).Run(&req) + {{end}} + if err != nil { utils.SendErrResponse(ctx, c, consts.StatusOK, err) return - } - {{end}} - {{if eq .OutputDir "" -}} - resp,err := service.New{{.Name}}Service(ctx, c).Run(&req) - {{else}} - resp,err := {{.OutputDir}}.New{{.Name}}Service(ctx, c).Run(&req) - {{end}} - if err != nil { - utils.SendErrResponse(ctx, c, consts.StatusOK, err) - return - } - utils.SendSuccessResponse(ctx, c, consts.StatusOK, resp) - }= - - path: "{{.HandlerDir}}/{{.GenPackage}}/{{ToSnakeCase .ServiceName}}_test.go" - loop_service: true - update_behavior: - type: "append" - append_key: "method" - insert_key: "Test{{$.Name}}" - append_tpl: |- - func Test{{.Name}}(t *testing.T) { - h := server.Default() - h.{{.HTTPMethod}}("{{.Path}}", {{.Name}}) - w := ut.PerformRequest(h.Engine, "{{.HTTPMethod}}", "{{.Path}}", &ut.Body{Body: bytes.NewBufferString(""), Len: 1}, - ut.Header{}) - resp := w.Result() - assert.DeepEqual(t, 201, resp.StatusCode()) - assert.DeepEqual(t, "", string(resp.Body())) - // todo edit your unit test. - } - body: |- - package {{.FilePackage}} - import ( - "bytes" - "testing" - - "github.com/cloudwego/hertz/pkg/app/server" - "github.com/cloudwego/hertz/pkg/common/test/assert" - "github.com/cloudwego/hertz/pkg/common/ut" - ) - {{range $_, $MethodInfo := $.Methods}} - func Test{{$MethodInfo.Name}}(t *testing.T) { - h := server.Default() - h.{{$MethodInfo.HTTPMethod}}("{{$MethodInfo.Path}}", {{$MethodInfo.Name}}) - w := ut.PerformRequest(h.Engine, "{{$MethodInfo.HTTPMethod}}", "{{$MethodInfo.Path}}", &ut.Body{Body: bytes.NewBufferString(""), Len: 1}, - ut.Header{}) - resp := w.Result() - assert.DeepEqual(t, 201, resp.StatusCode()) - assert.DeepEqual(t, "", string(resp.Body())) - // todo edit your unit test. - } - {{end}} + } + utils.SendSuccessResponse(ctx, c, consts.StatusOK, resp) + }= + - path: "{{.HandlerDir}}/{{.GenPackage}}/{{ToSnakeCase .ServiceName}}_test.go" + loop_service: true + update_behavior: + type: "append" + append_key: "method" + insert_key: "Test{{$.Name}}" + append_tpl: |- + func Test{{.Name}}(t *testing.T) { + h := server.Default() + h.{{.HTTPMethod}}("{{.Path}}", {{.Name}}) + w := ut.PerformRequest(h.Engine, "{{.HTTPMethod}}", "{{.Path}}", &ut.Body{Body: bytes.NewBufferString(""), Len: 1}, + ut.Header{}) + resp := w.Result() + assert.DeepEqual(t, 201, resp.StatusCode()) + assert.DeepEqual(t, "", string(resp.Body())) + // todo edit your unit test. + } + body: |- + package {{.FilePackage}} + import ( + "bytes" + "testing" + + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/common/test/assert" + "github.com/cloudwego/hertz/pkg/common/ut" + ) + {{range $_, $MethodInfo := $.Methods}} + func Test{{$MethodInfo.Name}}(t *testing.T) { + h := server.Default() + h.{{$MethodInfo.HTTPMethod}}("{{$MethodInfo.Path}}", {{$MethodInfo.Name}}) + w := ut.PerformRequest(h.Engine, "{{$MethodInfo.HTTPMethod}}", "{{$MethodInfo.Path}}", &ut.Body{Body: bytes.NewBufferString(""), Len: 1}, + ut.Header{}) + resp := w.Result() + assert.DeepEqual(t, 201, resp.StatusCode()) + assert.DeepEqual(t, "", string(resp.Body())) + // todo edit your unit test. + } + {{end}} ``` ## MVC Template Practice diff --git a/content/en/docs/hertz/tutorials/toolkit/usage-protobuf.md b/content/en/docs/hertz/tutorials/toolkit/usage-protobuf.md index da97e5e471..0bde360d9e 100644 --- a/content/en/docs/hertz/tutorials/toolkit/usage-protobuf.md +++ b/content/en/docs/hertz/tutorials/toolkit/usage-protobuf.md @@ -40,7 +40,7 @@ description: "hz usage(protobuf)." optional string js_conv = 50109; optional string file_name = 50110; optional string none = 50111; - + // 50131~50160 used to extend field option by hz optional string form_compatible = 50131; optional string js_conv_compatible = 50132; @@ -48,7 +48,7 @@ description: "hz usage(protobuf)." optional string none_compatible = 50134; // 50135 is reserved to vt_compatible // optional FieldRules vt_compatible = 50135; - + optional string go_tag = 51001; } @@ -70,7 +70,7 @@ description: "hz usage(protobuf)." optional string param = 50307; // Whether client requests take public parameters optional string baseurl = 50308; // Baseurl used in ttnet routing optional string handler_path = 50309; // handler_path specifies the path to generate the method - + // 50331~50360 used to extend method option by hz optional string handler_path_compatible = 50331; // handler_path specifies the path to generate the method } @@ -90,7 +90,7 @@ description: "hz usage(protobuf)." extend google.protobuf.MessageOptions { // optional FieldRules msg_vt = 50111; - + optional string reserve = 50830; // 550831 is reserved to msg_vt_compatible // optional FieldRules msg_vt_compatible = 50831; diff --git a/content/en/docs/hertz/tutorials/toolkit/usage-thrift.md b/content/en/docs/hertz/tutorials/toolkit/usage-thrift.md index 59cfb41fb9..4285ce3f7d 100644 --- a/content/en/docs/hertz/tutorials/toolkit/usage-thrift.md +++ b/content/en/docs/hertz/tutorials/toolkit/usage-thrift.md @@ -162,7 +162,7 @@ description: "hz usage(thrift)." 1. When writing the update command, you only need to specify the IDL file that defines the `service`. hz will automatically generate all the dependencies for that file. -3. As you can see +2. As you can see Add new method under `biz/handler/hello/example/hello_service.go`
The file `new_service.go` and the corresponding "NewMethod" method have been added under `biz/handler/hello/example`. @@ -191,13 +191,13 @@ description: "hz usage(thrift)." } ``` -4. Compile the project +3. Compile the project ```bash go build ``` -5. Run the project and test it +4. Run the project and test it Run the project: diff --git a/content/en/docs/kitex/Best Practice/Integration Testing/_index.md b/content/en/docs/kitex/Best Practice/Integration Testing/_index.md index 9aeee2939a..978021c554 100644 --- a/content/en/docs/kitex/Best Practice/Integration Testing/_index.md +++ b/content/en/docs/kitex/Best Practice/Integration Testing/_index.md @@ -5,4 +5,3 @@ weight: 4 date: 2024-02-18 description: "This doc describes how to mock client calls and efficient debug ideas." --- - diff --git a/content/en/docs/kitex/Best Practice/Integration Testing/debug_efficiently.md b/content/en/docs/kitex/Best Practice/Integration Testing/debug_efficiently.md index 820fc4375e..9849bb2b3d 100644 --- a/content/en/docs/kitex/Best Practice/Integration Testing/debug_efficiently.md +++ b/content/en/docs/kitex/Best Practice/Integration Testing/debug_efficiently.md @@ -4,7 +4,6 @@ linkTitle: "Debug Efficiently" weight: 2 date: 2024-02-18 description: > - --- ## Troubleshooting Panic Issues @@ -93,7 +92,7 @@ created by testing.(*T).Run panic: runtime error: slice bounds out of range [:5] with capacity 0 [recovered] panic: runtime error: slice bounds out of range [:5] with capacity 0 [recovered] panic: runtime error: slice bounds out of range [:5] with capacity 0 - + goroutine 18 [running]: testing.tRunner.func1.2(0x113c7c0, 0xc00011c000) /usr/local/go/src/testing/testing.go:1144 +0x332 @@ -106,7 +105,7 @@ created by testing.(*T).Run panic(0x113c7c0, 0xc00011c1. The panic cause is a "slice bounds out of range" error with a capacity of 0. ``` -​ The order of the panic stack trace goes from top to bottom, with the outermost function calls at the bottom. We need to find the first place where panic() is called, so we need to look for the bottommost section of runtime/panic.go, and the line below it indicates the actual code line where the panic is triggered. +​ The order of the panic stack trace goes from top to bottom, with the outermost function calls at the bottom. We need to find the first place where panic() is called, so we need to look for the bottommost section of runtime/panic.go, and the line below it indicates the actual code line where the panic is triggered. ### Tracing through Race Conditions @@ -195,7 +194,7 @@ type Response struct { //go:noinline func RPCCall(req *Request) *Response { resp := &Response{Data: []byte("hello")} - if req.Id%100 == 0 { // Logic Bug + if req.Id%100 == 0 { // Logic Bug go func() { resp.Data = []byte("world") }() @@ -474,7 +473,7 @@ Frame 12: /home/wangzhuowei/code/chore/main.go:41 (PC: 491101) 39: if item == nil && err != nil { 40: if merr, ok := err.(*MyError); ok { => 41: log.Printf("Buy[%d] get error: %v", id, merr.Error()) - 42: } + 42: } (dlv) print id 57 ``` @@ -573,4 +572,4 @@ func AddSSH(data *SSHData) { According to the code, this function stores a 6-byte object in the `cache` map for each `UserId`. Since the `main` function calls `AddSSH` 1000 times per second, it results in a memory leak of 6KB per second. Even if the program runs for an hour, it would only leak 21MB of data, which is insufficient to account for a 60MB leak within a minute. -However, upon closer examination of the `append` function, we discover that the returned slice object still holds a reference to the underlying array created by the original `randBytes` function. As long as there is a partial reference to the slice, the original object cannot be fully released. \ No newline at end of file +However, upon closer examination of the `append` function, we discover that the returned slice object still holds a reference to the underlying array created by the original `randBytes` function. As long as there is a partial reference to the slice, the original object cannot be fully released. diff --git a/content/en/docs/kitex/Best Practice/Integration Testing/mock_client.md b/content/en/docs/kitex/Best Practice/Integration Testing/mock_client.md index 9631dd113f..c5e173fe3e 100644 --- a/content/en/docs/kitex/Best Practice/Integration Testing/mock_client.md +++ b/content/en/docs/kitex/Best Practice/Integration Testing/mock_client.md @@ -4,7 +4,6 @@ linkTitle: " How To Mock A Kitex Client" weight: 1 date: 2024-02-18 description: > - --- ## Introduction @@ -41,7 +40,7 @@ func MockHello(ctx context.Context, req *hello.MyReq, callOptions ...callopt.Opt // Test the mock function for the client func TestClient(t *testing.T) { - + ctrl := gomock.NewController(t) defer ctrl.Finish() @@ -50,7 +49,7 @@ func TestClient(t *testing.T) { // Add the mock function client.EXPECT().Hello(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(MockHello).AnyTimes() - + // Make a mock call resp, err := client.Hello(context.Background(), &hello.MyReq{Name: "bd"}) if err == nil { diff --git a/content/en/docs/kitex/Best Practice/usage_attention.md b/content/en/docs/kitex/Best Practice/usage_attention.md index 00ae638265..e8f359db99 100644 --- a/content/en/docs/kitex/Best Practice/usage_attention.md +++ b/content/en/docs/kitex/Best Practice/usage_attention.md @@ -20,11 +20,11 @@ If there is indeed a scenario where asynchronous usage is required, there are tw "github.com/cloudwego/kitex/pkg/rpcinfo" ) // this creates a read-only copy of `ri` and attaches it to the new context - ctx2 := rpcinfo.FreezeRPCInfo(ctx) + ctx2 := rpcinfo.FreezeRPCInfo(ctx) go func(ctx context.Context) { // ... ri := rpcinfo.GetRPCInfo(ctx) // OK - + //... }(ctx2) ``` @@ -33,7 +33,7 @@ If there is indeed a scenario where asynchronous usage is required, there are tw ## Do not create a new Kitex client for each request -The Kitex client object manages resources related to remote configuration, service discovery cache, connection pool, and other Service-related resources. It creates several goroutines to perform various asynchronous update tasks. +The Kitex client object manages resources related to remote configuration, service discovery cache, connection pool, and other Service-related resources. It creates several goroutines to perform various asynchronous update tasks. If Kitex clients are frequently created, it will cause a sudden increase in CPU usage, frequent timeouts in RPC calls, service discovery, and remote configuration retrieval, as well as a large increase in the number of goroutines. **Correct usage**: Create a Kitex client for each downstream service being accessed, and cache it. Then, whenever you need to make a request to the downstream service, use the corresponding method of the cached Kitex client. The same client can be used concurrently and safely. diff --git a/content/en/docs/kitex/FAQ/_index.md b/content/en/docs/kitex/FAQ/_index.md index 3e769f93b8..2897b01abd 100644 --- a/content/en/docs/kitex/FAQ/_index.md +++ b/content/en/docs/kitex/FAQ/_index.md @@ -10,45 +10,56 @@ description: "Kitex Frequently Asked Questions and corresponding Answers." ## Kitex Framework **Q1: Does Kitex support Windows?** -* Yes. Kitex has already supported to compile and run in Windows since v0.4.0 version. And code generation tool support the Windows environment since v0.5.2. + +- Yes. Kitex has already supported to compile and run in Windows since v0.4.0 version. And code generation tool support the Windows environment since v0.5.2. **Q2: Does Kitex support HTTP?** -* Kitex does not specifically provide HTTP request support. For API gateway scenario, Kitex provides a [HTTP mapping generic call](/docs/kitex/tutorials/advanced-feature/generic-call/#2-http-mapping-generic-call) regarding Thrift and sends the Thrift encoding of the HTTP request to the server. -* For related support, please refer to another CloudWeGo HTTP framework [Hertz](/zh/docs/hertz/). + +- Kitex does not specifically provide HTTP request support. For API gateway scenario, Kitex provides a [HTTP mapping generic call](/docs/kitex/tutorials/advanced-feature/generic-call/#2-http-mapping-generic-call) regarding Thrift and sends the Thrift encoding of the HTTP request to the server. +- For related support, please refer to another CloudWeGo HTTP framework [Hertz](/zh/docs/hertz/). **Q3: How to configure multiplexing?** -* If you are using Thrift or Kitex Protobuf, to configure multiplexing: + +- If you are using Thrift or Kitex Protobuf, to configure multiplexing: 1. Configure WithMuxTransport() on your server. 2. Configure WithMuxConnection(1) on your client -* If you are using gRPC, multiplexing is configured by default. +- If you are using gRPC, multiplexing is configured by default. -**Q4: In the scenario of direct local call, why does the configuration of connection pool not take effect?** -* The ip of your local test needs to be 127.0.0.1. For example, "client.WithHostPorts("127.0.0.1:8888")". +**Q4: In the scenario of direct local call, why does the configuration of connection pool not take effect?** -**Q5: What are the differences between "Kitex Protobuf" and "gRPC" protocol?** -* Kitex Protobuf is a Protobuf Message Protocol defined by Kitex framework, with similar structure to Thrift. -* gRPC provides support to gRPC message protocol and enables Kitex to interact with gRPC framework. +- The ip of your local test needs to be 127.0.0.1. For example, "client.WithHostPorts("127.0.0.1:8888")". + +**Q5: What are the differences between "Kitex Protobuf" and "gRPC" protocol?** + +- Kitex Protobuf is a Protobuf Message Protocol defined by Kitex framework, with similar structure to Thrift. +- gRPC provides support to gRPC message protocol and enables Kitex to interact with gRPC framework. **Q6: Issues regarding Thrift interface compiling, such as "not enough arguments in call to iprot.ReadStructBegin"** -* Based on Thrift v0.13, Kitex cannot be upgraded directly, as there is a breaking change in the interface of Apache Thrift v0.14. The reason for such problems could be that a new version of Thrift is pulled during upgrades. The use of -u parameters is not recommended during upgrades, you can run the following command to fix the version: `go mod edit -replace github.com/apache/thrift=github.com/apache/thrift@v0.13.0` + +- Based on Thrift v0.13, Kitex cannot be upgraded directly, as there is a breaking change in the interface of Apache Thrift v0.14. The reason for such problems could be that a new version of Thrift is pulled during upgrades. The use of -u parameters is not recommended during upgrades, you can run the following command to fix the version: `go mod edit -replace github.com/apache/thrift=github.com/apache/thrift@v0.13.0` ## Kitex Code Generation Tool **Q1:'not enough arguments' problem when installing the code generation tool** -* Please try: "go mod:GO111MODULE=on go get github.com/cloudwego/kitex/tool/cmd/kitex@latest" + +- Please try: "go mod:GO111MODULE=on go get github.com/cloudwego/kitex/tool/cmd/kitex@latest" **Q2: Why 'set' in IDL becomes slice in generated codes?** -* Considering from JSON serialization, Starting from v0.11.0, Apache Thrift officially [changes the generation type of set from map to slice](https://issues.apache.org/jira/browse/THRIFT-4011). From a compatibility perspective, Kitex also follows the same rule. + +- Considering from JSON serialization, Starting from v0.11.0, Apache Thrift officially [changes the generation type of set from map to slice](https://issues.apache.org/jira/browse/THRIFT-4011). From a compatibility perspective, Kitex also follows the same rule. **Q3: Why is there an underscore after some field names?** -* The official implementation of Thrift restricts identifiers ending in "Result" and "Args" to avoid naming conflicts. The official Thrift conflict avoidance strategy: when the type name, service name and method name in the Thrift file start with New or end with Result or with Args, Thrift will automatically add an underscore at the end of the name. Referring to https://jira.apache.org/jira/browse/THRIFT-4410, Kitex uses Thriftgo for code generation. Thriftgo adopts a similar strategy in order to be as consistent as possible with the official implementation. + +- The official implementation of Thrift restricts identifiers ending in "Result" and "Args" to avoid naming conflicts. The official Thrift conflict avoidance strategy: when the type name, service name and method name in the Thrift file start with New or end with Result or with Args, Thrift will automatically add an underscore at the end of the name. Referring to https://jira.apache.org/jira/browse/THRIFT-4410, Kitex uses Thriftgo for code generation. Thriftgo adopts a similar strategy in order to be as consistent as possible with the official implementation. **Q4: Would code generated by new interface overwrite handler.go** -* Generated code under kitex_gen/ will be overwritten. But handler.go of server will not be overwritten, only new methods will be added correspondingly. + +- Generated code under kitex_gen/ will be overwritten. But handler.go of server will not be overwritten, only new methods will be added correspondingly. **Q5: Do the templates of the code generator support customization?** -* We have no plan to support template customization at present, because it will make the design for parameter passing much more complex. And the plugin mechanism can achieve almost any functionality equivalent to a customized template. + +- We have no plan to support template customization at present, because it will make the design for parameter passing much more complex. And the plugin mechanism can achieve almost any functionality equivalent to a customized template. **Q6: Is it possible for the '-type' argument of the code generator to be determined automatically by IDL filename extension?** -* Kitex already supports automatic file suffix determination in v0.4.0, there's no need to add the -type parameter. +- Kitex already supports automatic file suffix determination in v0.4.0, there's no need to add the -type parameter. diff --git a/content/en/docs/kitex/Getting started/_index.md b/content/en/docs/kitex/Getting started/_index.md index 22c654e12a..163270144f 100644 --- a/content/en/docs/kitex/Getting started/_index.md +++ b/content/en/docs/kitex/Getting started/_index.md @@ -5,7 +5,6 @@ weight: 2 date: 2024-01-18 keywords: ["Kitex", "Golang", "Go", "Getting Started", "Guidelines"] description: "This document covers the preparation of the development environment, quick start and basic tutorials of Kitex." - --- ## Overview diff --git a/content/en/docs/kitex/Getting started/examples.md b/content/en/docs/kitex/Getting started/examples.md index ad38495cd2..9702609e3d 100644 --- a/content/en/docs/kitex/Getting started/examples.md +++ b/content/en/docs/kitex/Getting started/examples.md @@ -5,7 +5,6 @@ weight: 5 date: 2024-01-18 keywords: ["Kitex", "Golang", "Go", "Examples"] description: "Code Examples for using Kitex" - --- ## How to run @@ -73,7 +72,7 @@ You can go into the related examples for information on "how to run" - [profiler](https://github.com/cloudwego/kitex-examples/tree/main/profiler) Example of Kitex server and client performance analysis using request cost metrics - [proxyless](https://github.com/cloudwego/kitex-examples/tree/main/proxyless) Example of letting Kitex services run in proxyless mode and be managed uniformly by the service mesh - [grpc_multi_service](https://github.com/cloudwego/kitex-examples/tree/main/grpc_multi_service) Example of Kitex server and client using grpc multiservice -- [goroutine_local_storage](https://github.com/cloudwego/kitex-examples/tree/main/goroutine-local-storage) Example of Kitex server and client using goroutine_local_storage +- [goroutine_local_storage](https://github.com/cloudwego/kitex-examples/tree/main/goroutine-local-storage) Example of Kitex server and client using goroutine_local_storage ## Kitex generated code diff --git a/content/en/docs/kitex/Getting started/pre-knowledge.md b/content/en/docs/kitex/Getting started/pre-knowledge.md index 95aa244e02..7e3b6a54d6 100644 --- a/content/en/docs/kitex/Getting started/pre-knowledge.md +++ b/content/en/docs/kitex/Getting started/pre-knowledge.md @@ -5,7 +5,6 @@ weight: 1 date: 2024-01-18 keywords: ["Kitex", "Golang", "Go", "Pre-knowledge"] description: "Pre-knowledge for using Kitex" - --- ## RPC @@ -23,7 +22,7 @@ An RPC invocation involves the following basic steps, divided into the client an 3. (Client) Serialize the request parameters into binary data. 4. (Client) Send the data to the server over the network. ------- +--- 1. (Server) The server receives the data. 2. (Server) Deserialize the request parameters. @@ -31,7 +30,7 @@ An RPC invocation involves the following basic steps, divided into the client an 4. (Server) Serialize the response into binary data. 5. (Server) Send the data back to the client over the network. ------- +--- 1. (Client) Receive the data. 2. (Client) Deserialize the response. @@ -97,7 +96,7 @@ Thrift provides strongly-typed containers that map to commonly used container ty Thrift supports type definitions similar to C/C++: ```thrift -typedef i32 MyInteger +typedef i32 MyInteger typedef Tweet ReTweet ``` @@ -113,7 +112,7 @@ Thrift provides enumeration types: - Nested enums are not supported. ```thrift -enum TweetType { +enum TweetType { TWEET, // 0 RETWEET = 2, // 2 DM = 0xa, // 10 @@ -189,14 +188,14 @@ A struct in Thrift is composed of different fields, where each field has a uniqu ```thrift struct Location { - 1: required double latitude; - 2: required double longitude; + 1: required double latitude; + 2: required double longitude; } -struct Tweet { +struct Tweet { 1: required i32 userId; 2: required string userName; - 3: required string text; + 3: required string text; 4: optional Location loc; // Struct can contain other structs 16: optional string language = "english" // Default value can be set } @@ -221,17 +220,17 @@ In Thrift, a service definition is semantically equivalent to an interface in OO > oneway itself does not guarantee reliability and has some special handling risks, so it is not recommended to use it. ```thrift -service Twitter { - // A method definition looks like C code. It has a return type, arguments, - // and optionally a list of exceptions that it may throw. Note that argument - // lists and exception list are specified using the exact same syntax as +service Twitter { + // A method definition looks like C code. It has a return type, arguments, + // and optionally a list of exceptions that it may throw. Note that argument + // lists and exception list are specified using the exact same syntax as // field lists in structs. - void ping(); // 1 - bool postTweet(1:Tweet tweet); // 2 + void ping(); // 1 + bool postTweet(1:Tweet tweet); // 2 TweetSearchResult searchTweets(1:string query); // 3 - - // The 'oneway' modifier indicates that the client only makes a request and does not wait for any response at all. Oneway methods MUST be void. + + // The 'oneway' modifier indicates that the client only makes a request and does not wait for any response at all. Oneway methods MUST be void. oneway void zip() // 4 } ``` @@ -304,4 +303,3 @@ To comply with the specifications for service invocations, Kitex imposes certain [Apache Thrift - Thrift Type System](https://thrift.apache.org/docs/types) [Thrift: The Missing Guide](https://diwakergupta.github.io/thrift-missing-guide/) - diff --git a/content/en/docs/kitex/Getting started/prerequisite.md b/content/en/docs/kitex/Getting started/prerequisite.md index 465a00293c..a00b28c7c2 100644 --- a/content/en/docs/kitex/Getting started/prerequisite.md +++ b/content/en/docs/kitex/Getting started/prerequisite.md @@ -69,4 +69,4 @@ After successful installation, execute `kitex --version` to see the specific ver ```bash $ kitex --version vx.x.x -``` \ No newline at end of file +``` diff --git a/content/en/docs/kitex/Getting started/quick_start.md b/content/en/docs/kitex/Getting started/quick_start.md index 41878cc65c..ca239d8f50 100644 --- a/content/en/docs/kitex/Getting started/quick_start.md +++ b/content/en/docs/kitex/Getting started/quick_start.md @@ -5,7 +5,6 @@ weight: 3 date: 2024-01-18 keywords: ["Kitex", "Golang", "Go", "Basic Example"] description: "Basic example for Kitex" - --- Before starting this section, make sure you have the required **Pre-knowledge** and have completed the **Environment Preparation**. @@ -29,7 +28,7 @@ Before starting this section, make sure you have the required **Pre-knowledge** ```bash go run . - + // Output similar logs indicating successful execution 2024/01/18 20:35:08.857352 server.go:83: [Info] KITEX: server listen at addr=[::]:8888 ``` @@ -38,7 +37,7 @@ Before starting this section, make sure you have the required **Pre-knowledge** ```bash go run ./client - + // Output similar logs every second indicating successful execution 2024/01/18 20:39:59 Response({Message:my request}) 2024/01/18 20:40:00 Response({Message:my request}) @@ -63,7 +62,7 @@ Before starting this section, make sure you have the required **Pre-knowledge** ```bash docker run --network host kitex-examples ./hello-server - + // Output similar logs indicating successful execution 2024/01/18 12:47:34.712415 server.go:83: [Info] KITEX: server listen at addr=[::]:8888 ``` @@ -72,7 +71,7 @@ Before starting this section, make sure you have the required **Pre-knowledge** ```bash docker run --network host kitex-examples ./hello-client - + // Output similar logs every second indicating successful execution 2024/01/18 12:48:20 Response({Message:my request}) 2024/01/18 12:48:21 Response({Message:my request}) @@ -224,4 +223,4 @@ Follow the same steps as before to run the server and client code. If you see ou 2024/01/18 21:07:57 AddResponse({Sum:1024}) ``` -Congratulations! You have completed all the steps to get started with Kitex! \ No newline at end of file +Congratulations! You have completed all the steps to get started with Kitex! diff --git a/content/en/docs/kitex/Getting started/tutorial.md b/content/en/docs/kitex/Getting started/tutorial.md index 07ad9791db..5f7def8b48 100644 --- a/content/en/docs/kitex/Getting started/tutorial.md +++ b/content/en/docs/kitex/Getting started/tutorial.md @@ -5,7 +5,6 @@ weight: 4 date: 2024-01-18 keywords: ["Kitex", "Golang", "Go", "Advanced Tutorial"] description: "Advanced Tutorial for Kitex" - --- Before starting this section, make sure you have an understanding of the **Pre-knowledge** and have completed the **Environment Preparation**. @@ -315,7 +314,7 @@ After successful compilation, the `output` directory will be generated: ``` output ├── bin // Contains the binary executable file -│ └── example.shop.item +│ └── example.shop.item └── bootstrap.sh // Script to run the file ``` @@ -364,7 +363,7 @@ if err != nil { } ``` -In the above code, `itemservice.NewClient` is used to create the client. The first parameter is the *service name* to invoke, and the second parameter is the *options* to pass in, where `client.WithHostPorts` is used to specify the address of the server. We can see that the item service is listening on port 8888 locally when running, so we specify port 8888. For more parameters, you can refer to the [Client Option](/docs/kitex/tutorials/options/client_options/) section. +In the above code, `itemservice.NewClient` is used to create the client. The first parameter is the _service name_ to invoke, and the second parameter is the _options_ to pass in, where `client.WithHostPorts` is used to specify the address of the server. We can see that the item service is listening on port 8888 locally when running, so we specify port 8888. For more parameters, you can refer to the [Client Option](/docs/kitex/tutorials/options/client_options/) section. ### Invoking the service @@ -391,7 +390,7 @@ The third parameter is the `options` for this invocation. Kitex provides a mecha ### Exposing an HTTP interface -You can use `net/http` or other frameworks to expose an HTTP interface. Here, we'll demonstrate a simple example using `Hertz`. You can get usage for Hertz in [Hertz Doc](/docs/hertz/) +You can use `net/http` or other frameworks to expose an HTTP interface. Here, we'll demonstrate a simple example using `Hertz`. You can get usage for Hertz in [Hertz Doc](/docs/hertz/) Here's the complete code: @@ -465,7 +464,7 @@ package main import ( "context" - + stock "example_shop/kitex_gen/example/shop/stock" ) @@ -585,7 +584,7 @@ func main() { if err != nil { log.Println(err.Error()) } -} +} ``` Since the stock service is running on port 8890, we specify that port when creating the client. @@ -611,7 +610,7 @@ You can see that `Stock: 1024`, indicating that our item service successfully re To simulate a real environment, we will now integrate our service with a registry. In this example, we have chosen etcd as the registry. You can refer to the installation and usage of etcd at [etcd.io](https://etcd.io/) or the following `docker compose` file. Assuming you have already installed and started the etcd service instance. ```yml -version: '3' +version: "3" services: etcd: @@ -722,7 +721,7 @@ package main import ( "log" - + item "example_shop/kitex_gen/example/shop/item/itemservice" "github.com/cloudwego/kitex/pkg/rpcinfo" @@ -736,7 +735,7 @@ func main() { if err != nil { log.Fatal(err) } - + itemServiceImpl := new(ItemServiceImpl) stockCli, err := NewStockClient("0.0.0.0:8890") if err != nil { @@ -844,7 +843,7 @@ func main() { log.Fatal(err) } cli = c - + hz := server.New(server.WithHostPorts("localhost:8889")) hz.GET("/api/item", Handler) @@ -871,4 +870,3 @@ In this section, we used Kitex to develop both the RPC server and client, and ac - On the client side, we used the same IDL as the server, generated the code using Kitex, created a client instance, and made the RPC call by constructing the request parameters. In this example, we only demonstrated the basic usage of Kitex. Kitex provides various microservice governance features. You can find more information in the [Guide](/docs/kitex/tutorials/) or explore the example code to unlock more advanced usage. - diff --git a/content/en/docs/kitex/Overview/_index.md b/content/en/docs/kitex/Overview/_index.md index 930dbfd801..1767030237 100644 --- a/content/en/docs/kitex/Overview/_index.md +++ b/content/en/docs/kitex/Overview/_index.md @@ -10,8 +10,8 @@ description: "This doc covers architecture design, features and performance of K Kitex [kaɪt'eks] is a **high-performance** and **strong-extensibility** Golang RPC framework that helps developers build microservices. If the performance and extensibility are the main concerns when you develop microservices, Kitex can be a good choice. - ### Architecture + ![image](/img/docs/kitex.png) ### Basic Features @@ -48,7 +48,7 @@ Kitex has built-in code generation tools that support generating **Thrift**, **P We compared the performance of Kitex with some popular RPC frameworks ([test code](https://github.com/cloudwego/kitex-benchmark)), such as [gRPC](https://github.com/grpc/grpc) and [RPCX](https://github.com/smallnest/rpcx), both using Protobuf protocol. The test results show that [Kitex](https://github.com/cloudwego/kitex) performs better. -*Note: The performance benchmarks obtained from the experiment are for reference only, because there are many factors that can affect the actual performance in application scenarios.* +_Note: The performance benchmarks obtained from the experiment are for reference only, because there are many factors that can affect the actual performance in application scenarios._ ### Test environment @@ -61,16 +61,16 @@ We compared the performance of Kitex with some popular RPC frameworks ([test cod Change the concurrency with a fixed packet size 1KB. -| QPS | TP99 | TP999 | -| :--------------------------------------------------- | :---------------------------------------------------: | :----------------------------------------------------: | +| QPS | TP99 | TP999 | +| :------------------------------------------------- | :-------------------------------------------------: | :--------------------------------------------------: | | ![image](/img/docs/performance_concurrent_qps.png) | ![image](/img/docs/performance_concurrent_tp99.png) | ![image](/img/docs/performance_concurrent_tp999.png) | ### Throughput performance Change packet size with a fixed concurrency of 100. -| QPS | TP99 | TP999 | -| :------------------------------------------------- | :-------------------------------------------------: | :--------------------------------------------------: | +| QPS | TP99 | TP999 | +| :----------------------------------------------- | :-----------------------------------------------: | :------------------------------------------------: | | ![image](/img/docs/performance_bodysize_qps.png) | ![image](/img/docs/performance_bodysize_tp99.png) | ![image](/img/docs/performance_bodysize_tp999.png) | ## Related Projects diff --git a/content/en/docs/kitex/Reference/_index.md b/content/en/docs/kitex/Reference/_index.md index 25238c614c..8a947fdf9d 100644 --- a/content/en/docs/kitex/Reference/_index.md +++ b/content/en/docs/kitex/Reference/_index.md @@ -4,5 +4,4 @@ linkTitle: "Reference" weight: 4 date: 2021-08-31 description: > - ---- \ No newline at end of file +--- diff --git a/content/en/docs/kitex/Reference/exception.md b/content/en/docs/kitex/Reference/exception.md index b41b69c16e..8b14397f47 100644 --- a/content/en/docs/kitex/Reference/exception.md +++ b/content/en/docs/kitex/Reference/exception.md @@ -98,7 +98,7 @@ These error is thrift Application Exception, usually these error will be wrapped ### Check whether a Kitex error -Use `IsKitexError` in `kerrors` package +Use `IsKitexError` in `kerrors` package ```go import "github.com/cloudwego/kitex/pkg/kerrors" @@ -151,5 +151,6 @@ if de.ErrorType() == kerrors.ErrInternalException {} // return true ``` `DetailedError` provide following functions to get detail message. + 1. `ErrorType() error`, used to get basic error type 2. `Stack() string`, used to get stack (for now only works for `ErrPanic`) diff --git a/content/en/docs/kitex/Tutorials/_index.md b/content/en/docs/kitex/Tutorials/_index.md index 93fae0ef40..87b9a3943d 100755 --- a/content/en/docs/kitex/Tutorials/_index.md +++ b/content/en/docs/kitex/Tutorials/_index.md @@ -5,5 +5,3 @@ weight: 3 date: 2022-12-23 description: Kitex Features Guide, including basic features, governance features, advanced features, code generation, framework extensions and options. --- - - diff --git a/content/en/docs/kitex/Tutorials/advanced-feature/GLS.md b/content/en/docs/kitex/Tutorials/advanced-feature/GLS.md index 56f8f62c85..0069a8ab99 100644 --- a/content/en/docs/kitex/Tutorials/advanced-feature/GLS.md +++ b/content/en/docs/kitex/Tutorials/advanced-feature/GLS.md @@ -2,7 +2,7 @@ title: "GLS Feature Usage" date: 2023-11-29 weight: 11 -keywords: ["GLS","context"] +keywords: ["GLS", "context"] description: "Goroutine local storage for implicitly pass context" --- @@ -37,7 +37,7 @@ func(prev, cur context.Context) (ctx context.Context, backup bool) - `Prev` parameter represents the context of the backup - `Cur` parameter represents the context obtained by the current client - `Ctx` return value represents the final context where the user completes processing -- `Backup` return value indicates whether to continue localsession [built-in fallback backup ](https://github.com/cloudwego/localsession/blob/main/backup/metainfo.go#L54), mainly metainfo Persistent KVS pass-through at present +- `Backup` return value indicates whether to continue localsession [built-in fallback backup ](https://github.com/cloudwego/localsession/blob/main/backup/metainfo.go#L54), mainly metainfo Persistent KVS pass-through at present ```go var expectedKey interface{} diff --git a/content/en/docs/kitex/Tutorials/advanced-feature/_index.md b/content/en/docs/kitex/Tutorials/advanced-feature/_index.md index c3a16ac9af..d2de7206e0 100644 --- a/content/en/docs/kitex/Tutorials/advanced-feature/_index.md +++ b/content/en/docs/kitex/Tutorials/advanced-feature/_index.md @@ -4,5 +4,4 @@ linkTitle: "Advanced Feature" weight: 4 date: 2021-08-31 description: > - --- diff --git a/content/en/docs/kitex/Tutorials/advanced-feature/codec_frugal.md b/content/en/docs/kitex/Tutorials/advanced-feature/codec_frugal.md index 02c9ab0192..af84760d2e 100644 --- a/content/en/docs/kitex/Tutorials/advanced-feature/codec_frugal.md +++ b/content/en/docs/kitex/Tutorials/advanced-feature/codec_frugal.md @@ -11,8 +11,9 @@ Github Project Page: https://github.com/cloudwego/frugal ## Usage Note: + 1. Frugal **can be used independently** on either server side or client side. - 1. The transmitted data are always encoded according to the standard thrift protocol + 1. The transmitted data are always encoded according to the standard thrift protocol 2. If Frugal is enabled on the server side, make sure that Framed (or TTHeaderFramed) is enabled on the client side. 3. If slim template is used, PayloadCodec must be specified to enable frugal. @@ -27,6 +28,7 @@ The Kitex Command Line tool has built-in frugal integration. ###### **Frugal Tag: -thrift frugal_tag** Generate Go structs with frugal tags, for example: + ```go type Request struct { Message string `thrift:"message,1" frugal:"1,default,string" json:"message"` @@ -34,11 +36,13 @@ type Request struct { ``` Note: + 1. Frugal relies on these tags. For example, set and list are both mapped to slice in golang, which can only be distinguished by frugal tag; 2. Without frugal tags, kitex will automatically fallback to the default Go codec (provided not using slim template); 3. If you don't want to generate frugal tags, use `-thrift frugal_tag=false`. Kitex >= v0.5.0 defaults to have this parameter specified; in older versions, you need to manually specify this parameter and execute the kitex command, for example: + ```bash kitex -thrift frugal_tag -service service_name idl/api.thrift ``` @@ -50,6 +54,7 @@ Call `frugal.Pretouch` method in `init()` to preprocess (JIT compile) all reques Frugal defaults to calling the JIT Compiler before the first encoding/decoding on a specific type, which may cause the first request to take longer. Example: + ```bash kitex -frugal-pretouch -service service_name idl/api.thrift ``` @@ -65,6 +70,7 @@ Here's the [example code](https://github.com/cloudwego/kitex-examples/blob/v0.2. Frugal uses JIT to generate codec code and does not rely on the generated Go codec. Example: + ```bash kitex -thrift frugal_tag,template=slim -service service_name idl/api.thrift ``` @@ -76,21 +82,25 @@ Note: Enabling Slim will result in no fallback and reporting an error when fruga It is recommended to use the latest version of Kitex (>= v0.5.0) and thriftgo (>= v0.3.0). ###### **Conservative version** + ```bash kitex -thrift frugal_tag -service service_name idl/api.thrift ``` Explain: + 1. New Kitex versions (>=v0.5.0) will generate frugal tags by default. 2. Do not use pretouch: commonly not all types are used in a project; you can try to enable it and observe whether it slows down the bootstrap of your service. 3. Do not use slim templates: In scenarios where frugal is not supported, fallback is applicable with the generated Go codec. ###### **Radical version** + ```bash kitex -thrift frugal_tag,template=slim -frugal-pretouch -service service_name idl/api.thrift ``` Explain: + 1. Pretouch enabled: may cause the process to start slowly 2. Slim template enabled: In scenarios that do not support frugal, fallback to the generated Go codec is not applicable, and an error will be reported. @@ -99,6 +109,7 @@ Explain: ##### Notes **Please ensure** that the client has `Framed` (or `TTHeaderFramed`) enabled. + - Enabling Framed ensures that the payload size is set in the header; - If the payload size is not available, currently Kitex Server can only fallback to the generated Go codec; - If it's using slim template, fallback is not available and an error will be reported: "decode failed, codec msg type not match". @@ -110,11 +121,12 @@ Related options for server initialization. ###### **server.WithPayloadCodec** For enabling Frugal: + ```go server.WithPayloadCodec( thrift.NewThriftCodecWithConfig(thrift.FrugalRead | thrift.FrugalWrite) ) -``` +``` Note: If an error is reported (symbol not found), it indicates that the combination of the current kitex version + go version does not support frugal. For example, Go 1.21 + Kitex v0.7.1 (unsupported versions are blocked through conditional compile). @@ -159,23 +171,28 @@ Related options for client initialization. ###### **client.WithPayloadCodec** For enabling Frugal: + ```go client.WithPayloadCodec( thrift.NewThriftCodecWithConfig(thrift.FrugalRead | thrift.FrugalWrite) ) ``` + Note: If an error is reported (no symbol found), it indicates that the combination of the current kitex version + go version does not support frugal, for example, Go 1.21 + Kitex v0.7.1 (unsupported versions are blocked through conditional compile). ###### **client.WithTransportProtocol** For enabling Framed: prepend a 4-byte (int32) length to indicate the size of thrift pure payload + ```go client.WithTransportProtocol(transport.Framed) ``` + Note: + 1. If Framed is not set, there may be issues: - 1. The server may not be able to decode with frugal without Payload Size (refer to: "Kitex Server -> Notes"); - 2. The server won't reply with a `Framed` payload, thus the Client may also not be able to decode with frugal (no Payload Size again); + 1. The server may not be able to decode with frugal without Payload Size (refer to: "Kitex Server -> Notes"); + 2. The server won't reply with a `Framed` payload, thus the Client may also not be able to decode with frugal (no Payload Size again); 2. If the target server does not support `Framed`, then don't use it; the client can encode without it, but if the response (from the server) is not Framed (i.e. with preprended payload size), the client may not be able to decode with Frugal (so in this case, do not use slim template); 3. `TTHeaderFramed` is an alternative (it's the BIT-OR result of `TTHeader | Framed`). @@ -216,6 +233,7 @@ In some scenarios (such as recording traffic), there's a need to call frugal dir Frugal's JIT compiler relies on Go structs with proper frugal tags. Note: + - A method may have multiple request arguments, so `frugal.EncodeObject` requires a Go struct encapsulating all these parameters in order. For example, the Struct [EchoEchoArgs](https://github.com/cloudwego/kitex-examples/blob/v0.2.1/kitex_gen/api/echo.go#L469) generated by Kitex encapsulates the [Request](https://github.com/cloudwego/kitex-examples/blob/v0.2.1/kitex_gen/api/echo.go#L12). - Although the response has only one parameter, it should also be encapsulated in a struct. For example, [EchoEchoResult](https://github.com/cloudwego/kitex-examples/blob/v0.2.1/kitex_gen/api/echo.go#L641) encapsulates [Response](https://github.com/cloudwego/kitex-examples/blob/v0.2.1/kitex_gen/api/echo.go#L176). - For details, please refer to the [example code](https://github.com/cloudwego/kitex-examples/blob/v0.2.2/frugal/codec/frugal.go). @@ -228,13 +246,15 @@ Note: kitex runs thriftgo to generate the structures. ##### Use thriftgo (>= v0.3.0) Install thriftgo ( >= v0.3.0): + ```bash go install -v github.com/cloudwego/thriftgo@latest ``` Generate Go Structs based on a Thrift IDL: + ```bash -thriftgo -r -o thrift -g go:frugal_tag,template=slim,package_prefix=github.com/example echo.thrift +thriftgo -r -o thrift -g go:frugal_tag,template=slim,package_prefix=github.com/example echo.thrift ``` ##### Manually (Not Recommended) @@ -242,15 +262,17 @@ thriftgo -r -o thrift -g go:frugal_tag,template=slim,package_prefix=github.com/e Please refer to the struct generated by thriftgo (e.g. [Request](https://github.com/cloudwego/kitex-examples/blob/v0.2.1/kitex_gen/api/echo.go#L12), [Response](https://github.com/cloudwego/kitex-examples/blob/v0.2.1/kitex_gen/api/echo.go#L176)). Note: + 1. Each field should have a frugal tag. 2. For optional fields, default values should be set in the `InitDefault()`` method. 3. Construct structs that encapsulate request/response arguments (e.g. [EchoEchoArgs](https://github.com/cloudwego/kitex-examples/blob/v0.2.1/kitex_gen/api/echo.go#L469), [EchoEchoResult](https://github.com/cloudwego/kitex-examples/blob/v0.2.1/kitex_gen/api/echo.go#L641)) -#### Encoding +#### Encoding If you only want to use thrift codec (for example, to replace JSON), you can directly call `frugal.EncodeObject(..)`. If you want to generate a Thrift Payload that conforms to the [Thrift Binary protocol encoding](https://github.com/apache/thrift/blob/master/doc/specs/thrift-binary-protocol.md) (which can be sent to the Thrift Server), the encoding result should include: + 1. Thrift Magic Number: int16, the fixed value 0x8001 2. MessageType: int16, enumeration values, CALL = 1, REPLY = 2, Exception = 3, Oneway = 4 3. MethodName: length (int32) + name ([]byte) @@ -264,6 +286,7 @@ Note: `data` should be a struct that encapsulates all request/response parameter #### Decoding According to Thrift Binary protocol encoding, decode result should contain: + 1. MethodName 2. MessageType 3. Sequence ID @@ -349,9 +372,10 @@ UnmarshalAllSize_Parallel/large-16 4.80k ± 0% 0.76k ± 0% -84.10% Run kitex with `-thrift frugal_tag=false`. Note: + 1. If frugal tags are not generated, you can not use frugal codec - 1. In Golang, Thrift's set and list are both mapped to slice, and can only be distinguished by frugal tags. - 2. If Kitex detects that the request/response type does not contain a tag, it will NOT use frugal, and fallback to the standard Go codec. + 1. In Golang, Thrift's set and list are both mapped to slice, and can only be distinguished by frugal tags. + 2. If Kitex detects that the request/response type does not contain a tag, it will NOT use frugal, and fallback to the standard Go codec. 2. If slim template is used, frugal tags must be generated. ### Kitex Client Reporting "encode failed: codec msg type not match with thriftCodec" @@ -361,6 +385,7 @@ Error message reported by client: > failed with error: remote or network error[remote]: encode failed, codec msg type not match with thriftCodec Possible reasons: + - Using the slim template **WITHOUT** specifying client.PayloadCodec; - Using the slim template **WITHOUT** generating frugal tags for Structs; @@ -371,6 +396,7 @@ Error message reported by server (or in the client's log): > decode failed, codec msg type not match with thriftCodec Possible reasons: + - Using the slim template **WITHOUT** specifying server.PayloadCodec; - Using the slim template **WITHOUT** generating frugal tags for Structs - The client is **NOT** sending Thrift payload with `Framed` or `TTHeaderFramed` @@ -392,9 +418,10 @@ New versions have NOCOPY mode disabled by default, which can be fixed after upgr ### Error reported compiling Kitex projects: "undefined: thrift.FrugalRead" Possible reasons: + 1. Compiling with unsupported Go versions: please compile with go1.16 ~ go1.21; 2. The Kitex version does not support the Go version used: please upgrade to the latest Kitex - 1. For example: Kitex v0.7.1 have frugal disabled when compiling with go1.21 (go1.21 was not supported by frugal when releasing these versions). Upgrading to Kitex >= v0.7.2 will fix it. + 1. For example: Kitex v0.7.1 have frugal disabled when compiling with go1.21 (go1.21 was not supported by frugal when releasing these versions). Upgrading to Kitex >= v0.7.2 will fix it. ### Optional fields are not filled with defaults with Slim template @@ -420,4 +447,4 @@ go get github.com/cloudwego/frugal@latest If the problem still exists, please confirm that the object being encoded is not being read and written concurrently (including objects indirectly referenced). -For example, if a string variable is being set to an empty string, a read on it may get an invalid string object (StringHeader.Data = nil && StringHeader.Len > 0), which will cause a "nil pointer error" panic when encoding. \ No newline at end of file +For example, if a string variable is being set to an empty string, a read on it may get an invalid string object (StringHeader.Data = nil && StringHeader.Len > 0), which will cause a "nil pointer error" panic when encoding. diff --git a/content/en/docs/kitex/Tutorials/advanced-feature/error_handler.md b/content/en/docs/kitex/Tutorials/advanced-feature/error_handler.md index 57d05e77ea..d742049da1 100644 --- a/content/en/docs/kitex/Tutorials/advanced-feature/error_handler.md +++ b/content/en/docs/kitex/Tutorials/advanced-feature/error_handler.md @@ -21,7 +21,7 @@ server.WithErrorHandler(yourServerErrorHandler) This function is executed after the server-side handler and before the middleware is executed, and can be used to return custom error codes and messages to the client-side. Note that although this is supported, business-level custom error codes are still not recommended to be handled by ErrorHandler, because we want to distinguish RPC errors from business errors, which indicate a failed RPC request, such as timeout, circuit breaker, rate limiting, which is a failed request at the RPC level, but business errors are at the business logic level, which is actually a successful request at the RPC level. Kitex will develop a [custom exception specification](https://github.com/cloudwego/kitex/issues/511) to distinguish between business errors and RPC level errors. -* ErrorHandler example: +- ErrorHandler example: Kitex wraps the error returned by the server handler as kerrors.ErrBiz, if you want to get the original error you need to Unwrap it first. @@ -30,7 +30,7 @@ This function is executed after the server-side handler and before the middlewar func ServerErrorHandler(ctx context.Context, err error) error { // if you want get other rpc info, you can get rpcinfo first, like `ri := rpcinfo.GetRPCInfo(ctx)` // for example, get remote address: `remoteAddr := rpcinfo.GetRPCInfo(ctx).From().Address()` - + if errors.Is(err, kerrors.ErrBiz) { err = errors.Unwrap(err) } @@ -64,13 +64,13 @@ client.WithErrorHandler(yourClientErrorHandler) The handler is executed after the remote call and before the middleware is executed. The framework has a default ClientErrorHandler, it will be used by default if no ClientErrorHandler is configured. The behavior of the default Handler is to return **ErrRemoteOrNetwork** when an error is received from the server-side or when an exception occurs at the transport layer on the client side. In addition, for Thrift and KitexProtobuf, the error msg contains a '[remote]' message to identify that it is an error on the other side; for gRPC, if the other side returns an error constructed by `status.Error`, use `status.FromError(err)` on the local side to get `*status.Status`, note that `Status` needs to be provided by Kitex, the package path is `github.com/cloudwego/kitex/pkg/remote/trans/nphttp2/status`. -* ErrorHandler example: +- ErrorHandler example: ```go func ClientErrorHandler(ctx context.Context, err error) error { // if you want get other rpc info, you can get rpcinfo first, like `ri := rpcinfo.GetRPCInfo(ctx)` // for example, get remote address: `remoteAddr := rpcinfo.GetRPCInfo(ctx).To().Address()` - + // for thrift、KitexProtobuf if e, ok := err.(*remote.TransError); ok { // TypeID is error code @@ -88,9 +88,9 @@ func ClientErrorHandler(ctx context.Context, err error) error { Because some of the error codes are built-in to the framework, users should avoid using the built-in error codes, currently built-in error codes: -* Thrift、KitexProtobuf:0 - 10。 +- Thrift、KitexProtobuf:0 - 10。 -* gRPC:0 - 17。 +- gRPC:0 - 17。 ## ErrorHandler Execution Mechanism diff --git a/content/en/docs/kitex/Tutorials/advanced-feature/generic-call/basic_usage.md b/content/en/docs/kitex/Tutorials/advanced-feature/generic-call/basic_usage.md index 84c58c17c6..25a1814f08 100644 --- a/content/en/docs/kitex/Tutorials/advanced-feature/generic-call/basic_usage.md +++ b/content/en/docs/kitex/Tutorials/advanced-feature/generic-call/basic_usage.md @@ -734,7 +734,7 @@ func main() { // resp type is map[string]interface{} resp, err := cli.GenericCall(ctx, "ExampleMethod", map[string]interface{}{ "Msg": "hello", - }) + }) } ``` diff --git a/content/en/docs/kitex/Tutorials/advanced-feature/generic-call/generic-call-reflection.md b/content/en/docs/kitex/Tutorials/advanced-feature/generic-call/generic-call-reflection.md index 104578c474..f99c383ede 100644 --- a/content/en/docs/kitex/Tutorials/advanced-feature/generic-call/generic-call-reflection.md +++ b/content/en/docs/kitex/Tutorials/advanced-feature/generic-call/generic-call-reflection.md @@ -6,11 +6,11 @@ keywords: ["dynamic", "thrift", "generic-call"] description: "Use Thrift reflection to improve generic-call performance" --- -## What is Thrift Reflection ? +## What is Thrift Reflection ? In short, **similar to [pb reflect](https://pkg.go.dev/google.golang.org/protobuf/reflect/protoreflect), it does not rely on static code to add, delete, modify, and write Thrift data** . -Reflection uses specific generics to describe any data at runtime. Compared with static struct, it has the characteristics of **flexible addition, deletion, and modification, and does not depend on static code** . Currently [dynamicgo](https://github.com/cloudwego/dynamicgo) has implemented a set of reflection APIs for the thrift binary protocol, which can be roughly divided into Thrift Value/Node and Thrift DOM according to usage scenarios. +Reflection uses specific generics to describe any data at runtime. Compared with static struct, it has the characteristics of **flexible addition, deletion, and modification, and does not depend on static code** . Currently [dynamicgo](https://github.com/cloudwego/dynamicgo) has implemented a set of reflection APIs for the thrift binary protocol, which can be roughly divided into Thrift Value/Node and Thrift DOM according to usage scenarios. ## Thrift Value/Node @@ -18,13 +18,13 @@ Used for the **addition, deletion, modification, and lookup of a small number of ## Thrift DOM -The **document object tree model** is used to **describe the full deserialization of Thrift data** . Since the Thrift protocol itself has self-description ability, we can deserialize it into a specific tree structure for more complex **container traversal , field bit shifting** and other operations. Specific business scenarios include **DSL mapping, data packet merging**, etc. in BFF services. Dynamicgo provides [thrift/generic. PathNode ](https://github.com/cloudwego/dynamicgo/blob/main/thrift/generic/README.md#type-pathnode)encapsulation, which can handle thrift data of arbitrary complexity without binding dynamic type descriptions. +The **document object tree model** is used to **describe the full deserialization of Thrift data** . Since the Thrift protocol itself has self-description ability, we can deserialize it into a specific tree structure for more complex **container traversal , field bit shifting** and other operations. Specific business scenarios include **DSL mapping, data packet merging**, etc. in BFF services. Dynamicgo provides [thrift/generic. PathNode ](https://github.com/cloudwego/dynamicgo/blob/main/thrift/generic/README.md#type-pathnode)encapsulation, which can handle thrift data of arbitrary complexity without binding dynamic type descriptions. ## Why use Thrift generics instead of Kitex Map/JSON generalization calls ? In short: **better performance** . -Thrift generic requirements generally come from **rpc generalization calls, http < > rpc protocol conversion** and other centralized API gateways\ BFF scenarios, often with high performance requirements. However, Kitex Map/JSON generalization calls are implemented in the current map + interface mode, which inevitably brings a large number of fragmented heap memory allocation , and its performance is far worse than that of kitex rpc services in normal code generation mode. In contrast, both the efficient skip algorithm of Thrift Value and the carefully designed memory structure of Thrift DOM can effectively avoid a large number of runtime memory allocation and intermediate codec conversion. See [introduction](https://github.com/cloudwego/dynamicgo/blob/main/introduction.md) for detailed design and implementation. +Thrift generic requirements generally come from **rpc generalization calls, http < > rpc protocol conversion** and other centralized API gateways\ BFF scenarios, often with high performance requirements. However, Kitex Map/JSON generalization calls are implemented in the current map + interface mode, which inevitably brings a large number of fragmented heap memory allocation , and its performance is far worse than that of kitex rpc services in normal code generation mode. In contrast, both the efficient skip algorithm of Thrift Value and the carefully designed memory structure of Thrift DOM can effectively avoid a large number of runtime memory allocation and intermediate codec conversion. See [introduction](https://github.com/cloudwego/dynamicgo/blob/main/introduction.md) for detailed design and implementation. For specific comparison results, please refer to the section "Test Data" below. @@ -61,7 +61,7 @@ func (g *ExampleValueServiceImpl) GenericCall(ctx context.Context, method string if err != nil { return nil, err } - + // wrap response as thrift REPLY message return dt.WrapBinaryBody(resp, methodName, dt.REPLY, 0, seqID) } @@ -291,7 +291,7 @@ func MakeExampleReqBinary(B bool, A string, logid string) ([]byte, error) { } ``` -3. Encapsulates thrift binary message, initiates binary generalization call +3. Encapsulates thrift binary message, initiates binary generalization call ```go func TestThriftReflect(t *testing.T) { @@ -355,7 +355,7 @@ func ExampleClientHandler_DOM(response []byte, log_id string) error { if err != nil { return err } - // spew.Dump(root) // -- only root.Next is set + // spew.Dump(root) // -- only root.Next is set // check node values by PathNode APIs require_field2, err := root.Field(2, DynamicgoOptions).Node.String() if err != nil { @@ -364,7 +364,7 @@ func ExampleClientHandler_DOM(response []byte, log_id string) error { if require_field2 != ReqMsg { return errors.New("require_field2 does not match") } - + // load **all layers** children err = root.Load(true, DynamicgoOptions) if err != nil { @@ -393,11 +393,13 @@ Note that **memory pooling is used for DOM access** , which can greatly improve - Thrift [reflect](https://github.com/cloudwego/kitex/blob/cc85ab10fbdc7519c90ed7b25e2533127a1ddd82/pkg/generic/reflect_test/reflect_test.go) - [Map](https://github.com/cloudwego/kitex/blob/cc85ab10fbdc7519c90ed7b25e2533127a1ddd82/pkg/generic/reflect_test/map_test.go) + - Testing environment - goos: darwin - goarch: amd64 - cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz + - Test results Small Data (266B) @@ -471,6 +473,5 @@ func GetNewRequest(idXX int, nameXX string) []byte { ## Attention -1. Currently dynamicgo only supports **thrift-binary** encoding mode +1. Currently dynamicgo only supports **thrift-binary** encoding mode 2. Currently, binary generalization only supports the **thrift-framed** transport protocol - diff --git a/content/en/docs/kitex/Tutorials/advanced-feature/generic-call/thrift_idl_annotation_standards.md b/content/en/docs/kitex/Tutorials/advanced-feature/generic-call/thrift_idl_annotation_standards.md index 6060da84d1..57da62668e 100644 --- a/content/en/docs/kitex/Tutorials/advanced-feature/generic-call/thrift_idl_annotation_standards.md +++ b/content/en/docs/kitex/Tutorials/advanced-feature/generic-call/thrift_idl_annotation_standards.md @@ -6,9 +6,9 @@ weight: 3 description: > --- -| date | version | author | update content | -| --- | ---- | ------ | ------------ | -| 2022-05-22 | v1.0 | wangjingpei | first version of IDL Definition Specification for Mapping between Thrift and HTTP | +| date | version | author | update content | +| ---------- | ------- | ----------- | --------------------------------------------------------------------------------- | +| 2022-05-22 | v1.0 | wangjingpei | first version of IDL Definition Specification for Mapping between Thrift and HTTP | This specification is the IDL definition standard for mapping between Thrift and HTTP. It contains definition standards of service, endpoint, `request` and `response` parameters. Kitex partially implements the specification, and the parts of annotation description indicate if it is supported. @@ -30,23 +30,23 @@ This specification is the IDL definition standard for mapping between Thrift and #### Restrict -1. We should specify the name and type of associated HTTP API parameters, such as header, cookie and name by annotations. If not specified, the GET method corresponds to query parameters, while the POST method corresponds to body parameters automatically. The field name is used as parameter key -2. If the HTTP request uses GET method, `api.body` annotation occurred in request definitions is invalid. Only annotations such as `api.query`, `api.path` or `api.cookie` are supported +1. We should specify the name and type of associated HTTP API parameters, such as header, cookie and name by annotations. If not specified, the GET method corresponds to query parameters, while the POST method corresponds to body parameters automatically. The field name is used as parameter key +2. If the HTTP request uses GET method, `api.body` annotation occurred in request definitions is invalid. Only annotations such as `api.query`, `api.path` or `api.cookie` are supported 3. If one HTTP request uses POST method and the serialization strategy is `form`, the request field type like `object` and `map` is not supported. But Kitex doesn't support form now, only `json` format. #### Annotation Description -| annotation | description | field restrict | is KiteX supported | -| --- | ---- | ------ | ----- | -| `api.query` | ` api.query `corresponds url query parameter for HTTP request | Only basic types (except for `object`, `map` ) and `list` split by , are supported | ✅| -| `api.path` | `api.query` corresponds url path parameter for HTTP request | Only basic types are supported | ✅| -| `api.header` | `api.header` corresponds header parameter for HTTP request | Only basic type and list split by , are supported | ✅| -| `api.cookie` | `api. cookie `corresponds cookie parameter for HTTP request | Only basic types are supported | ✅| -|` api.body` | `api.body `corresponds body parameter for HTTP request
Both serialization type like `json` and `form` in body are supported | `Json` is supported by default . The `api.serializer` annotation for `method` can sepify serialization `json or form` | ✅, but only `json` format | -| `api.raw_body` | `api.raw_body` corresponds raw body for HTTP request, we can get raw binary body | | ✅| -| `api.vd` | Parameter valid, we can refer [HTTPs://github.com/bytedance/go-tagexpr/tree/master/validator](HTTPs://github.com/bytedance/go-tagexpr/tree/master/validator) for details | | ❌ | -| `api.js_conv` | `api.js_conv` indicates the field should be string while the definition is in64, since int64 is not supported by typescript |The annotation value should be `true`, if else will be treated as invalid | ✅| -| `api.raw_uri` | `api.raw_uri` is used for protocol exchange from HTTP to RPC, the RPC service can get the raw uri by the field | Only `string` type is supported | ❌ | +| annotation | description | field restrict | is KiteX supported | +| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- | -------------------------- | +| `api.query` | `api.query`corresponds url query parameter for HTTP request | Only basic types (except for `object`, `map` ) and `list` split by , are supported | ✅ | +| `api.path` | `api.query` corresponds url path parameter for HTTP request | Only basic types are supported | ✅ | +| `api.header` | `api.header` corresponds header parameter for HTTP request | Only basic type and list split by , are supported | ✅ | +| `api.cookie` | `api. cookie `corresponds cookie parameter for HTTP request | Only basic types are supported | ✅ | +| ` api.body` | `api.body `corresponds body parameter for HTTP request
Both serialization type like `json` and `form` in body are supported | `Json` is supported by default . The `api.serializer` annotation for `method` can sepify serialization `json or form` | ✅, but only `json` format | +| `api.raw_body` | `api.raw_body` corresponds raw body for HTTP request, we can get raw binary body | | ✅ | +| `api.vd` | Parameter valid, we can refer [HTTPs://github.com/bytedance/go-tagexpr/tree/master/validator](HTTPs://github.com/bytedance/go-tagexpr/tree/master/validator) for details | | ❌ | +| `api.js_conv` | `api.js_conv` indicates the field should be string while the definition is in64, since int64 is not supported by typescript | The annotation value should be `true`, if else will be treated as invalid | ✅ | +| `api.raw_uri` | `api.raw_uri` is used for protocol exchange from HTTP to RPC, the RPC service can get the raw uri by the field | Only `string` type is supported | ❌ | #### Example @@ -83,15 +83,15 @@ struct BizRequest { #### Annotation Description -| annotation | description | field restrict | is KiteX supported | -| --- | ---- | ------ | ----- | -| `api.header` | `api.header` corresponds `header` parameter for HTTP response | Only basic types and `list` split by , are supported | ✅| -| `api.http_code` | `api.http_code` corresponds HTTP code for HTTP response,such as 200, 500 and so on |The annotation value should be `true`, if else will be treated as invalid | ✅| -| `api.body` | `api.body` corresponds `body` parameter for HTTP response | | ✅| -| `api.none` | `api.body` indicates the field will be ignored for HTTP `response` |The annotation value should be `true`, if else will be treated as invalid | ✅| -| `api.js_conv` | `api.js_conv` indicates the field should be trans to `string` in response since it is int64 |The annotation value should be `true`, if else will be treated as invalid| ✅| -| `api.raw_body` | `api.raw_body` indicates the field will be treated as raw body for response | | ✅| -| `api.cookie` | `api.cookie` indicates the field will be treated as cookie for HTTP response | | ✅| +| annotation | description | field restrict | is KiteX supported | +| --------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | ------------------ | +| `api.header` | `api.header` corresponds `header` parameter for HTTP response | Only basic types and `list` split by , are supported | ✅ | +| `api.http_code` | `api.http_code` corresponds HTTP code for HTTP response,such as 200, 500 and so on | The annotation value should be `true`, if else will be treated as invalid | ✅ | +| `api.body` | `api.body` corresponds `body` parameter for HTTP response | | ✅ | +| `api.none` | `api.body` indicates the field will be ignored for HTTP `response` | The annotation value should be `true`, if else will be treated as invalid | ✅ | +| `api.js_conv` | `api.js_conv` indicates the field should be trans to `string` in response since it is int64 | The annotation value should be `true`, if else will be treated as invalid | ✅ | +| `api.raw_body` | `api.raw_body` indicates the field will be treated as raw body for response | | ✅ | +| `api.cookie` | `api.cookie` indicates the field will be treated as cookie for HTTP response | | ✅ | #### Example @@ -120,18 +120,18 @@ struct BizResponse { #### Restrict - The serialization specified by the `api.serializer` is valid for GET request -- Each URI corresponds one `method` in IDL by annotation, the annotation must be written +- Each URI corresponds one `method` in IDL by annotation, the annotation must be written #### Annotation Description -| annotation | type | description | example | is KiteX supported | -| --- | ---- | --- | --- | ------ | -| `api.get` | `string` | `api.get` corresponds GET method, the value is the HTTP path, the uri syntex is in accord with gin( we can refer [httprouter](https://github.com/julienschmidt/httprouter) for detail) | `api.get = '/life/client/favorite/collect'` | ✅| -| `api.post` | `string` | `api.post` corresponds POST method, the uri syntex is in accord with gin( we can refer [httprouter](https://github.com/julienschmidt/httprouter) for detail) | `api.post='/life/client/favorite/collect'` | ✅| -| `api.put` | `string` | `api.put` corresponds PUT method, the uri syntex is in accord with gin( we can refer [httprouter](https://github.com/julienschmidt/httprouter) for detail) | `api.put='/life/client/favorite/collect'` | ✅| -| `api.delete` | `string` | `api.delete` corresponds DELETE method, the uri syntex is in accord with gin( we can refer [httprouter](https://github.com/julienschmidt/httprouter) for detail) | `api.delete='/life/client/favorite/collect'` | ✅| -| `api.patch` | `string` | `api.delete` corresponds DELETE method, the uri syntex is in accord with gin( we can refer [httprouter](https://github.com/julienschmidt/httprouter) for detail) | `api.patch='/life/client/favorite/collect'` | ✅| -| `api.serializer` | `string` | Request serialization type of client request | Such as `form`, `json`, `thrift` or `pb` | ❌ | +| annotation | type | description | example | is KiteX supported | +| ---------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | ------------------ | +| `api.get` | `string` | `api.get` corresponds GET method, the value is the HTTP path, the uri syntex is in accord with gin( we can refer [httprouter](https://github.com/julienschmidt/httprouter) for detail) | `api.get = '/life/client/favorite/collect'` | ✅ | +| `api.post` | `string` | `api.post` corresponds POST method, the uri syntex is in accord with gin( we can refer [httprouter](https://github.com/julienschmidt/httprouter) for detail) | `api.post='/life/client/favorite/collect'` | ✅ | +| `api.put` | `string` | `api.put` corresponds PUT method, the uri syntex is in accord with gin( we can refer [httprouter](https://github.com/julienschmidt/httprouter) for detail) | `api.put='/life/client/favorite/collect'` | ✅ | +| `api.delete` | `string` | `api.delete` corresponds DELETE method, the uri syntex is in accord with gin( we can refer [httprouter](https://github.com/julienschmidt/httprouter) for detail) | `api.delete='/life/client/favorite/collect'` | ✅ | +| `api.patch` | `string` | `api.delete` corresponds DELETE method, the uri syntex is in accord with gin( we can refer [httprouter](https://github.com/julienschmidt/httprouter) for detail) | `api.patch='/life/client/favorite/collect'` | ✅ | +| `api.serializer` | `string` | Request serialization type of client request | Such as `form`, `json`, `thrift` or `pb` | ❌ | #### Example diff --git a/content/en/docs/kitex/Tutorials/advanced-feature/metainfo.md b/content/en/docs/kitex/Tutorials/advanced-feature/metainfo.md index 8daab1f414..3d1d06b4e4 100644 --- a/content/en/docs/kitex/Tutorials/advanced-feature/metainfo.md +++ b/content/en/docs/kitex/Tutorials/advanced-feature/metainfo.md @@ -12,7 +12,7 @@ As an RPC framework, Kitex services communicate with each other through protocol However, in the production environment, we somehow may need to send special information to a remote server and that information is temporary or has an unstable format which can not be explicitly defined in the IDL. Such a situation requests the framework to be capable of sending meta information. -**NOTE** *MUST use the underlying transport protocol that supports passthrough of meta information,such as TTHeader, gRPC, HTTP*。 +**NOTE** _MUST use the underlying transport protocol that supports passthrough of meta information,such as TTHeader, gRPC, HTTP_。 To decouple with the underlying transport protocols, and interoperate with other frameworks, Kitex does not provide APIs to read or write meta information directly. Instead, it uses a stand-alone library [metainfo][metainfo] to support meta information transmitting. @@ -111,19 +111,20 @@ func (MyServiceImpl) SomeMethod(ctx context.Context, req *SomeRequest) (res *Som } ``` - [metainfo]: https://pkg.go.dev/github.com/bytedance/gopkg/cloud/metainfo ## Kitex gRPC metadata -Kitex gRPC scenarios can also use metainfo. But note that the key of the CGI gateway style interface in the format of uppercase + '_' needs to be satisfied. +Kitex gRPC scenarios can also use metainfo. But note that the key of the CGI gateway style interface in the format of uppercase + '\_' needs to be satisfied. In addition to metainfo usage, it is also compatible with the original metadata transmission method. But the two cannot be mixed. Similar to native gRPC, the forward pass is implemented through metadata. Reverse transmission is sent back through Header or Trailer, the specific usage is as follows: ### Forward + Client send settings: + ```golang ctx := metadata. AppendToOutgoingContext(ctx, "k1", "v1", "k1", "v2", "k2", "v3") // unary scene @@ -131,7 +132,9 @@ Client send settings: // stream scene stream, err := client. CallStream(ctx) ``` + Server receives: + ```golang // unary scene md, ok := metadata. FromIncomingContext(ctx) @@ -139,19 +142,22 @@ Server receives: md, ok := metadata.FromIncomingContext(stream.Context()) ``` - - ### Backward + #### Unary + In the unary scenario, the server sends meta information to the client as follows: Server settings: + ```golang nphttp2. SendHeader(ctx, metadata. Pairs("k1", "v1")) nphttp2. SetHeader(ctx, metadata. Pairs("k1", "v1")) nphttp2. SetTrailer(ctx, metadata. Pairs("k2", "v2")) ``` + Client receives: + ```golang // set in advance var header, trailer metadata.MD @@ -163,14 +169,19 @@ Client receives: log.Println("header is ", header) log.Println("trailer is ", trailer) ``` + #### Streaming + In the Streaming scenario, the server sends meta information to the client as follows: Server sends: + ```golang stream.SetHeader(metadata. Pairs("k1", "v1")) stream.SetTrailer(metadata. Pairs("k2","v2")) ``` + Client receives: + ```golang // After stream call md, _ := stream.Header() diff --git a/content/en/docs/kitex/Tutorials/advanced-feature/multi_service.md b/content/en/docs/kitex/Tutorials/advanced-feature/multi_service.md index 304b9e7b35..58b9fadb26 100644 --- a/content/en/docs/kitex/Tutorials/advanced-feature/multi_service.md +++ b/content/en/docs/kitex/Tutorials/advanced-feature/multi_service.md @@ -190,19 +190,20 @@ options = append(options, server.WithMiddleware(yourMiddleware)) svr := server.NewServer(options...) ``` + You can distinguish each request by the service/method with the usage shown before. ### Distinguish Streaming/Non-Streaming Methods The recommended way to determine whether a request has an underlying protocol for Streaming would be to check the type of the request/response arguments: -| | **Client Middleware** | **Server Middleware** | -|-------------------------------------|--------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| **Bidirectional**
**(gRPC)** | - request: `interface{}` = nil
- response: *streaming.Result | - request: *streaming.Args
- response: `interface{}` = nil | -| **Client Streaming**
**(gRPC)** | - request: interface{} = nil
- response: *streaming.Result | - request: *streaming.Args
- response: `interface{}` = nil | -| **Server Streaming**
**(gRPC)** | - request: `interface{}` = nil
- response: *streaming.Result | - request: *streaming.Args
- response: `interface{}` = nil | -| **Unary (gRPC)** | - request: *kitex_gen/some_pkg.${svc}${method}Args
- response: *kitex_gen/some_pkg.${svc}${method}Result | - request: *streaming.Args
- response: `interface{}` = nil
Note: the option provided since v0.9.0: `server.WithCompatibleMiddlewareForUnary()` makes it the same with PingPong API | -| **PingPong API (KitexPB)** | - request: *kitex_gen/some_pkg.${svc}${method}Args
- response: *kitex_gen/some_pkg.${svc}${method}Result | - request: *kitex_gen/some_pkg.${svc}${method}Args
- response: *kitex_gen/some_pkg.${svc}${method}Result | +| | **Client Middleware** | **Server Middleware** | +| ----------------------------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Bidirectional**
**(gRPC)** | - request: `interface{}` = nil
- response: \*streaming.Result | - request: \*streaming.Args
- response: `interface{}` = nil | +| **Client Streaming**
**(gRPC)** | - request: interface{} = nil
- response: \*streaming.Result | - request: \*streaming.Args
- response: `interface{}` = nil | +| **Server Streaming**
**(gRPC)** | - request: `interface{}` = nil
- response: \*streaming.Result | - request: \*streaming.Args
- response: `interface{}` = nil | +| **Unary (gRPC)** | - request: *kitex_gen/some_pkg.${svc}${method}Args
- response: *kitex_gen/some_pkg.${svc}${method}Result | - request: \*streaming.Args
- response: `interface{}` = nil
Note: the option provided since v0.9.0: `server.WithCompatibleMiddlewareForUnary()` makes it the same with PingPong API | +| **PingPong API (KitexPB)** | - request: *kitex_gen/some_pkg.${svc}${method}Args
- response: *kitex_gen/some_pkg.${svc}${method}Result | - request: *kitex_gen/some_pkg.${svc}${method}Args
- response: *kitex_gen/some_pkg.${svc}${method}Result | **NOTE:** Kitex server supports auto-detection on incoming requests, and for GRPC/Protobuf Unary methods, it accepts both GRPC requests and KitexProtobuf(TTHeader + Pure Protobuf Payload) requests, so **it may not be accurate to rely solely on the method name from RPCInfo**. diff --git a/content/en/docs/kitex/Tutorials/advanced-feature/profiler.md b/content/en/docs/kitex/Tutorials/advanced-feature/profiler.md index 2b4de9ebe2..5b52c6bd84 100644 --- a/content/en/docs/kitex/Tutorials/advanced-feature/profiler.md +++ b/content/en/docs/kitex/Tutorials/advanced-feature/profiler.md @@ -64,7 +64,7 @@ svr := xxxserver.NewServer(server.WithProfilerMessageTagging(msgTagging)) ### Write Processor functions -Kitex will periodically run callback functions with statistical results. If we have a metric system, we can upload results in the processor function. +Kitex will periodically run callback functions with statistical results. If we have a metric system, we can upload results in the processor function. For example, if we want to log the results: diff --git a/content/en/docs/kitex/Tutorials/advanced-feature/xds.md b/content/en/docs/kitex/Tutorials/advanced-feature/xds.md index 310a2e1023..27b25428bb 100644 --- a/content/en/docs/kitex/Tutorials/advanced-feature/xds.md +++ b/content/en/docs/kitex/Tutorials/advanced-feature/xds.md @@ -13,25 +13,28 @@ Kitex supports xDS API via the extension of [kitex-contrib/xds](https://github.c ## Feature -* Service Discovery -* Traffic Route: only support `exact` match for `method` and support `exact` `prefix` `regex` match for `header`. - * [HTTP route configuration](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/http/http_routing#arch-overview-http-routing): configure via [VirtualService](https://istio.io/latest/docs/reference/config/networking/virtual-service/). - * [ThriftProxy](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto): configure via patching [EnvoyFilter](https://istio.io/latest/docs/reference/config/networking/envoy-filter/). -* Timeout: - * Configuration inside `HTTP route configuration`: configure via VirtualService. +- Service Discovery +- Traffic Route: only support `exact` match for `method` and support `exact` `prefix` `regex` match for `header`. + - [HTTP route configuration](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/http/http_routing#arch-overview-http-routing): configure via [VirtualService](https://istio.io/latest/docs/reference/config/networking/virtual-service/). + - [ThriftProxy](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto): configure via patching [EnvoyFilter](https://istio.io/latest/docs/reference/config/networking/envoy-filter/). +- Timeout: + - Configuration inside `HTTP route configuration`: configure via VirtualService. ## Usage + There are two steps for enabling xDS for Kitex applications: 1. xDS module initialization and 2. Kitex Client/Server Option configuration. ### xDS module + To enable xDS mode in Kitex, we should invoke `xds.Init()` to initialize the xds module, including the `xdsResourceManager` and `xdsClient`. #### Bootstrap + The `xdsClient` is responsible for the interaction with the xDS Server (i.e. Istio). It needs some environment variables for initialization, which need to be set inside the `spec.containers.env` of the Kubernetes Manifest file in YAML format. -* `POD_NAMESPACE`: the namespace of the current service. -* `POD_NAME`: the name of this pod. -* `INSTANCE_IP`: the ip of this pod. +- `POD_NAMESPACE`: the namespace of the current service. +- `POD_NAME`: the name of this pod. +- `INSTANCE_IP`: the ip of this pod. Add the following part to the definition of your container that uses xDS-enabled Kitex client. @@ -55,7 +58,7 @@ valueFrom: For now, we only provide the support on the client-side. To use a xds-enabled Kitex client, you should specify `destService` using the URL of your target service and add one option `WithXDSSuite`. -* Construct a `xds.ClientSuite` that includes `RouteMiddleware` and `Resolver`, and then pass it into the `WithXDSSuite` option. +- Construct a `xds.ClientSuite` that includes `RouteMiddleware` and `Resolver`, and then pass it into the `WithXDSSuite` option. ``` // import "github.com/cloudwego/kitex/pkg/xds" @@ -66,7 +69,7 @@ client.WithXDSSuite(xds.ClientSuite{ }), ``` -* The URL of the target service should be in the format, which follows the format in [Kubernetes](https://kubernetes.io/): +- The URL of the target service should be in the format, which follows the format in [Kubernetes](https://kubernetes.io/): ``` ..svc.cluster.local: @@ -80,8 +83,9 @@ client.WithXDSSuite(xds.ClientSuite{ We can define traffic route configuration via [VirtualService](https://istio.io/latest/docs/reference/config/networking/virtual-service/) in Istio. The following example indicates that when the tag meets one of the conditions in the header, the request will be routed to the `v1` subcluster of `kitex-server`. + - `stage` exact match `canary` -- `userid` prefix match `2100` +- `userid` prefix match `2100` - `env` regex match `[dev|sit]` ``` @@ -114,7 +118,8 @@ spec: To match the rule defined in VirtualService, we can use `client.WithTag(key, val string)` or `callopt.WithTag(key, val string)`to specify the tags, which will be used to match the rules. -* Set key and value to be "stage" and "canary" to match the above rule defined in VirtualService. +- Set key and value to be "stage" and "canary" to match the above rule defined in VirtualService. + ``` client.WithTag("stage", "canary") callopt.WithTag("stage", "canary") @@ -126,7 +131,7 @@ Same as above, using [VirtualService](https://istio.io/latest/docs/reference/con The example below shows that requests with method equal to SayHello are routed to the `v1` subcluster of `kitex-server`. It should be noted that when defining rules, you need to include package name and service name, corresponding to `namespace` and `service` in thrift idl. -* uri: `/${PackageName}.${ServiceName}/${MethodName}` +- uri: `/${PackageName}.${ServiceName}/${MethodName}` ``` apiVersion: networking.istio.io/v1alpha3 @@ -150,8 +155,8 @@ spec: timeout: 0.5s ``` - ## Example + The usage is as follows: ``` @@ -190,7 +195,9 @@ func main() { Detailed examples can be found here [kitex-proxyless-example](https://github.com/cloudwego/kitex-examples/tree/main/proxyless). ## Limitation + ### mTLS + mTLS is not supported for now. Please disable mTLS via configuring PeerAuthentication. ``` @@ -205,10 +212,11 @@ spec: ``` ### Limited support for Service Governance + Current version only support Service Discovery, Traffic route and Timeout Configuration via xDS on the client-side. Other features supported via xDS, including Load Balancing, Rate Limit and Retry etc., will be added in the future. - ## Dependencies + Kitex >= v0.4.0 diff --git a/content/en/docs/kitex/Tutorials/basic-feature/_index.md b/content/en/docs/kitex/Tutorials/basic-feature/_index.md index 2b2ae88557..d338806c07 100644 --- a/content/en/docs/kitex/Tutorials/basic-feature/_index.md +++ b/content/en/docs/kitex/Tutorials/basic-feature/_index.md @@ -4,5 +4,4 @@ linkTitle: "Basic Feature" weight: 1 date: 2021-08-31 description: > - ---- \ No newline at end of file +--- diff --git a/content/en/docs/kitex/Tutorials/basic-feature/acquire_rpcinfo.md b/content/en/docs/kitex/Tutorials/basic-feature/acquire_rpcinfo.md index 34c38b62e8..4acd646783 100644 --- a/content/en/docs/kitex/Tutorials/basic-feature/acquire_rpcinfo.md +++ b/content/en/docs/kitex/Tutorials/basic-feature/acquire_rpcinfo.md @@ -12,14 +12,14 @@ The default lifecycle of Kitex's RPCInfo is from the start of the request to the ### 1.1 Synchronous usage -| **Information obtained** | **Kitex fetch method** | -| -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| Get Caller's Service | caller, ok := kitexutil.GetCaller(ctx) | -| Get RPC Method | method, ok := kitexutil.GetMethod(ctx) | -| Get Caller's address | cluster, ok := kitexutil.GetCallerAddr(ctx) | -| Get ServiceName defined in IDL | svcName, ok := kitexutil.GetIDLServiceName(ctx) | -| Get caller's handler method | callerMethod, ok := kitexutil.GetCallerHandlerMethod(ctx)
Only the caller is a Kitex server will have this method information by default, or you can set K_METHOD into context.Context then kitex will get it. | -| Get the transport protocol | tp, ok := kitexutil.GetTransportProtocol(ctx) | +| **Information obtained** | **Kitex fetch method** | +| -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Get Caller's Service | caller, ok := kitexutil.GetCaller(ctx) | +| Get RPC Method | method, ok := kitexutil.GetMethod(ctx) | +| Get Caller's address | cluster, ok := kitexutil.GetCallerAddr(ctx) | +| Get ServiceName defined in IDL | svcName, ok := kitexutil.GetIDLServiceName(ctx) | +| Get caller's handler method | callerMethod, ok := kitexutil.GetCallerHandlerMethod(ctx)
Only the caller is a Kitex server will have this method information by default, or you can set K_METHOD into context.Context then kitex will get it. | +| Get the transport protocol | tp, ok := kitexutil.GetTransportProtocol(ctx) | | Get the remote address from the caller-side. | ctx = metainfo.WithBackwardValues(ctx)
// set ctx first,then execute RPC call ...
err, resp := cli.YourMethod(ctx, req)
rip, ok := metainfo.GetBackwardValue(ctx, consts.RemoteAddr)
Note: Not applicable to oneway method | ### 1.2 Asynchronous usage @@ -35,11 +35,11 @@ import ( "github.com/cloudwego/kitex/pkg/utils/kitexutil" ) // this creates a read-only copy of `ri` and attaches it to the new context -ctx2 := rpcinfo.FreezeRPCInfo(ctx) +ctx2 := rpcinfo.FreezeRPCInfo(ctx) go func(ctx context.Context) { // ... ri := rpcinfo.GetRPCInfo(ctx) // OK - + // eg: get client psm // caller, ok := kitexutil.GetCaller(ctx) //... diff --git a/content/en/docs/kitex/Tutorials/basic-feature/bizstatuserr.md b/content/en/docs/kitex/Tutorials/basic-feature/bizstatuserr.md index b7c19c4cc7..db925f9d28 100644 --- a/content/en/docs/kitex/Tutorials/basic-feature/bizstatuserr.md +++ b/content/en/docs/kitex/Tutorials/basic-feature/bizstatuserr.md @@ -6,17 +6,18 @@ keywords: ["Kitex", "Custom Exception"] description: "Kitex has provided business custom exceptions since v0.4.3. This doc covers the interface definition, user usage, and framework implementation." --- -Business custom exceptions is convenient for users to use err that implements a specific interface to transmit business exceptions, so as to distinguish them from RPC exceptions. -An RPC exception usually indicates a failure of an RPC request, such as timeout, circuit breaker, or current limit. From the RPC level, it is a failed request. -But the business error belongs to the business logic level, at the RPC level, the request is actually successful. -It is recommended for service monitoring to report RPC errors as request failures and business-level errors as success, and use the additional biz_status_code field to report business exception status codes. +Business custom exceptions is convenient for users to use err that implements a specific interface to transmit business exceptions, so as to distinguish them from RPC exceptions. +An RPC exception usually indicates a failure of an RPC request, such as timeout, circuit breaker, or current limit. From the RPC level, it is a failed request. +But the business error belongs to the business logic level, at the RPC level, the request is actually successful. +It is recommended for service monitoring to report RPC errors as request failures and business-level errors as success, and use the additional biz_status_code field to report business exception status codes. This ability has certain value for engineering practice. ## BizStatusError interface definition -The built-in `BizStatusErrorIface` provides a business exception interfaces. The framework also provides default implementations, and users can also customize implementations. + +The built-in `BizStatusErrorIface` provides a business exception interfaces. The framework also provides default implementations, and users can also customize implementations. The gRPC business Error can implement `GRPCStatusIface` at the same time, so as to reuse the Detail of Status to transparently transmit richer business information. -````go +```go type BizStatusErrorIface interface { BizStatusCode() int32 BizMessage() string @@ -28,7 +29,7 @@ type GRPCStatusIface interface { GRPCStatus() *status.Status SetGRPCStatus(status *status.Status) } -```` +``` ## Instructions for use @@ -38,7 +39,7 @@ You can use the `NewBizStatusError` or `NewBizStatusErrorWithExtra` function in Use TTHeader as transport protocol: -````go +```go // Server side func (*MyServiceHandler) TestError(ctx context.Context, req *myservice.Request) (r *myservice.Response, err error) { // ... @@ -53,12 +54,13 @@ cli := myservice.MustNewClient("client", client.WithTransportProtocol(transport. client.WithMetaHandler(transmeta.ClientTTHeaderHandler)) resp, err := cli.TestError(ctx, req) bizErr, isBizErr := kerrors.FromBizStatusError(err) -```` +``` To pass additional gRPC Detail, use `NewGRPCBizStatusError` or `NewGRPCBizStatusErrorWithExtra` to construct an exception: + > Note: gRPC users can still use `NewBizStatusError` or `NewBizStatusErrorWithExtra` if not needed to pass gRPC Detail. -````go +```go // Server side func (*Handler) Serve(ctx, Request) (Response, error) { bizErr := kerrors.NewGRPCBizStatusError(404, "not found") @@ -82,7 +84,7 @@ if err != nil { // ... } } -```` +``` ### Middleware: Obtain/Return BizStatusError @@ -108,8 +110,8 @@ if setter, ok := ri.Invocation().(rpcinfo.InvocationSetter); ok { } ``` - ## Framework implementation + It relies on transport protocols to transparently transmit the error code and error information of business exceptions. Thrift and Kitex Protobuf rely on TTHeader, and Kitex gRPC relies on HTTP2. - Thrift: use TTHeader diff --git a/content/en/docs/kitex/Tutorials/basic-feature/connection_type.md b/content/en/docs/kitex/Tutorials/basic-feature/connection_type.md index 327441b90b..d6b5c59677 100644 --- a/content/en/docs/kitex/Tutorials/basic-feature/connection_type.md +++ b/content/en/docs/kitex/Tutorials/basic-feature/connection_type.md @@ -2,11 +2,12 @@ title: "Connection Type" date: 2023-10-16 weight: 4 -keywords: ["Kitex", "Short Connection", "Long Connection", "Connection Multiplexing"] +keywords: + ["Kitex", "Short Connection", "Long Connection", "Connection Multiplexing"] description: "Kitex supports short connections, long connection pool, connection multiplexing and connection pool status monitoring." --- -Kitex provides **Short Connection**, **Long Connection Pool** and **Connection Multiplexing** for different business scenarios. +Kitex provides **Short Connection**, **Long Connection Pool** and **Connection Multiplexing** for different business scenarios. Kitex uses **Long Connection Pool by default** after v0.0.2, but adjusting the Pool Config according to your need is suggested. ## Short Connection @@ -45,23 +46,26 @@ Parameter description: - `MinIdlePerAddress`(Kitex >= v0.4.3) - the minimum number of idle connections per downstream instance, which will not be cleaned up even if the idle time exceeds the `MaxIdleTimeout`. - For now, `MinIdlePerAddress` should be less than 5. + ### Internal Implementation Each downstream address corresponds to a connection pool, the connection pool is a ring composed of connections, and the size of the ring is `MaxIdlePerAddress`. When getting a connection of downstream address, proceed as follows: + 1. Try to fetch a connection from the pool, if fetching failed (no idle connections remained), then try to establish a new connection. In other words, the number of connections may exceed `MaxIdlePerAddress` 2. If fetching succeed, then check whether the idle time of the connection (since the last time it was placed in the connection pool) has exceeded MaxIdleTimeout. If yes, this connection will be closed and a new connection will be created. When the connection is ready to be returned after used, proceed as follows: 1. Check whether the connection is normal, if not, close it directly -2. Check whether the idle connection number exceeds `MaxIdleGlobal`, and if yes, close it directly +2. Check whether the idle connection number exceeds `MaxIdleGlobal`, and if yes, close it directly 3. Check whether free space remained in the pool of the target connection pool. If yes, put it into the pool, otherwise close it directly ### Parameter Setting Suggestion The setting of parameters is suggested as follows: + - `MaxIdlePerAddress`: the minimum value is 1, otherwise long connections would degenerate to short connections - What value should be set should be determined according to the throughput of downstream address. The approximate estimation formula is: `MaxIdlePerAddress = qps_per_dest_host*avg_response_time_sec` - For example, the cost of each request is 100ms, and the request spread to each downstream address is 100QPS, the value is suggested to set to 10, because each connection handles 10 requests per second, 100QPS requires 10 connections to handle @@ -69,7 +73,7 @@ The setting of parameters is suggested as follows: - Summary: this value be set too large or too small would lead to degenerating to the short connection - `MaxIdleGlobal`: should be larger than the total number of `downstream targets number * MaxIdlePerAddress` - Notice: this value is not very valuable, it is suggested to set it to a super large value. In subsequent versions, considers discarding this parameter and providing a new interface - - Since v0.7.2, no limit for `MaxIdleGlobal` if not set. + - Since v0.7.2, no limit for `MaxIdleGlobal` if not set. - `MaxIdleTimeout`: since the server will clean up inactive connections within 10min, the client also needs to clean up long-idle connections in time to avoid using invalid connections. This value cannot exceed 10min when the downstream is also a Kitex service - `MinIdlePerAddress` (Kitex >= v0.4.3): Assuming that there are periodic requests and the period is greater than `MaxIdleTimeout`, setting this parameter can avoid creating a new connection every time. - The parameter consideration is similar to `MaxIdlePerAddress` and can be set according to the average latency of requests and the throughput. diff --git a/content/en/docs/kitex/Tutorials/basic-feature/message_type.md b/content/en/docs/kitex/Tutorials/basic-feature/message_type.md index 8a88a6a23a..f324d4967c 100644 --- a/content/en/docs/kitex/Tutorials/basic-feature/message_type.md +++ b/content/en/docs/kitex/Tutorials/basic-feature/message_type.md @@ -10,11 +10,11 @@ description: Kitex supports message types of PingPong、Oneway、Streaming. The table below is message types, codecs and transports supported by Kitex. -|Message Types|Codec| Transport| -|--------|-------|--------| -|PingPong|Thrift / Protobuf| [TTHeader](../../../reference/transport_protocol_ttheader) / HTTP2(gRPC) | -|Oneway|Thrift| [TTHeader](../../../reference/transport_protocol_ttheader)| -|Streaming|Protobuf| HTTP2(gRPC)| +| Message Types | Codec | Transport | +| ------------- | ----------------- | ------------------------------------------------------------------------ | +| PingPong | Thrift / Protobuf | [TTHeader](../../../reference/transport_protocol_ttheader) / HTTP2(gRPC) | +| Oneway | Thrift | [TTHeader](../../../reference/transport_protocol_ttheader) | +| Streaming | Protobuf | HTTP2(gRPC) | - PingPong: the client always waits for a response after sending a request - Oneway: the client does not expect any response after sending a request @@ -107,7 +107,7 @@ import ( "xx/echo" "xx/echo/echoservice" - + "github.com/cloudwego/kitex/client" ) @@ -140,7 +140,7 @@ import ( "xx/echo" "xx/echo/echoservice" - + "github.com/cloudwego/kitex/client" ) @@ -164,9 +164,9 @@ func main() { Kitex supports two kinds of protocols that carry Protobuf payload: - Kitex Protobuf - - Only supports the PingPong type of messages. If any streaming method is defined in the IDL, the protocol will switch to gRPC. + - Only supports the PingPong type of messages. If any streaming method is defined in the IDL, the protocol will switch to gRPC. - The gRPC Protocol - - Be able to interoperate with gRPC. Use the same definition as gRPC service, and supports Unary (PingPong) and Streaming calls. + - Be able to interoperate with gRPC. Use the same definition as gRPC service, and supports Unary (PingPong) and Streaming calls. ### Example @@ -283,7 +283,7 @@ func (handler) BidiSideStreaming(stream echo.EchoService_BidiSideStreamingServer time.Sleep(time.Second) } }() - + err = <-errChan cancel() return err diff --git a/content/en/docs/kitex/Tutorials/basic-feature/protocol/_index.md b/content/en/docs/kitex/Tutorials/basic-feature/protocol/_index.md index 530750bc7f..62d4a4f920 100644 --- a/content/en/docs/kitex/Tutorials/basic-feature/protocol/_index.md +++ b/content/en/docs/kitex/Tutorials/basic-feature/protocol/_index.md @@ -4,5 +4,4 @@ linkTitle: "Protocol" weight: 2 date: 2024-01-06 description: > - --- diff --git a/content/en/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/binary.md b/content/en/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/binary.md index 8605328d45..a3724043a4 100644 --- a/content/en/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/binary.md +++ b/content/en/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/binary.md @@ -2,7 +2,7 @@ title: "Binary" date: 2024-01-06 weight: 1 -keywords: [ "Kitex", "Serialization", "Binary", "Thrift" ] +keywords: ["Kitex", "Serialization", "Binary", "Thrift"] description: Kitex uses the Binary protocol for serialization. --- diff --git a/content/en/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/hessian2.md b/content/en/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/hessian2.md index 6f1903f933..8b16306de1 100644 --- a/content/en/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/hessian2.md +++ b/content/en/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/hessian2.md @@ -2,7 +2,7 @@ title: "Hessian2" date: 2024-01-06 weight: 3 -keywords: [ "Kitex", "Serialization", "Hessian2" ] +keywords: ["Kitex", "Serialization", "Hessian2"] description: Kitex uses the Hessian2 protocol for serialization. --- diff --git a/content/en/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/protobuf.md b/content/en/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/protobuf.md index 0f9d47ef27..e970d968d7 100644 --- a/content/en/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/protobuf.md +++ b/content/en/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/protobuf.md @@ -2,7 +2,7 @@ title: "Protobuf" date: 2024-01-06 weight: 2 -keywords: [ "Kitex", "Serialization", "Protobuf" ] +keywords: ["Kitex", "Serialization", "Protobuf"] description: Kitex uses the Protobuf protocol for serialization. --- diff --git a/content/en/docs/kitex/Tutorials/basic-feature/protocol/transport-streaming/_index.md b/content/en/docs/kitex/Tutorials/basic-feature/protocol/transport-streaming/_index.md index 4660ef6e0c..57cd4fb745 100644 --- a/content/en/docs/kitex/Tutorials/basic-feature/protocol/transport-streaming/_index.md +++ b/content/en/docs/kitex/Tutorials/basic-feature/protocol/transport-streaming/_index.md @@ -4,5 +4,4 @@ linkTitle: "Transport Streaming" weight: 3 date: 2024-03-09 description: > - --- diff --git a/content/en/docs/kitex/Tutorials/basic-feature/protocol/transport-streaming/thrift_streaming.md b/content/en/docs/kitex/Tutorials/basic-feature/protocol/transport-streaming/thrift_streaming.md index 6ba4b481dd..0799a73441 100644 --- a/content/en/docs/kitex/Tutorials/basic-feature/protocol/transport-streaming/thrift_streaming.md +++ b/content/en/docs/kitex/Tutorials/basic-feature/protocol/transport-streaming/thrift_streaming.md @@ -2,7 +2,7 @@ title: "Thrift Streaming" date: 2024-03-09 weight: 2 -keywords: [ "Kitex", "Streaming", "Thrift"] +keywords: ["Kitex", "Streaming", "Thrift"] description: This article describes how to define and use the Streaming API in Thrift IDL. --- @@ -17,6 +17,7 @@ Many business scenarios \(such as LLM's streaming response and large-scale data #### PingPong API \(KitexThrift\) Kitex's default mode of Thrift APIs. + - Only support Ping-Pong request/response \(no Streaming\). - Thrift Payload may have prefixed [TTHeader](/docs/kitex/reference/transport_protocol_ttheader/)、[Framed](https://github.com/apache/thrift/blob/0.13.0/doc/specs/thrift-rpc.md#framed-vs-unframed-transport),or their combination \(TTHeader + Framed + Payload\). @@ -33,13 +34,16 @@ If there's really a need, you can enable it with an annotation in your Thrift ID There are 3 kinds of Streaming APIs \(referring to [grpc core concepts](https://grpc.io/docs/what-is-grpc/core-concepts/)\). ##### Server Streaming + The client sends a message, the server returns multiple messages, and then closes the stream. It's suitable for LLM scenarios. ##### Client Streaming + The client sends multiple messages, the server returns one message, and then closes the stream. ##### Bidirectional Streaming + The sending and receiving of Client/Server are independent, which can be organized in arbitrary order. ## Streaming over HTTP2 @@ -61,18 +65,19 @@ go install github.com/cloudwego/kitex/tool/cmd/kitex@latest Kitex determines the Streaming type of a method through the `streaming.mode` annotation. -| Value | Meaning | Extra Note | -|---------------|-------------------------|-----------------------------------------------------------------------------| -| bidirectional | Bidirectional streaming | The sending and receiving of Client/Server are independent | -| client | Client Side Streaming | The client sends multiple messages, the server returns one message | -| server | Server Side Streaming | The client sends a message, the server returns multiple messages | -| unary | Unary over Streaming | Client sends a Message, the Server returns a Message (Not recommended due to performance loss) | -| \(other\) | Invalid, leading to an error | | +| Value | Meaning | Extra Note | +| ------------- | ---------------------------- | ---------------------------------------------------------------------------------------------- | +| bidirectional | Bidirectional streaming | The sending and receiving of Client/Server are independent | +| client | Client Side Streaming | The client sends multiple messages, the server returns one message | +| server | Server Side Streaming | The client sends a message, the server returns multiple messages | +| unary | Unary over Streaming | Client sends a Message, the Server returns a Message (Not recommended due to performance loss) | +| \(other\) | Invalid, leading to an error | | NOTE: + 1. Streaming API should have exactly one request and one response, otherwise Kitex will report an error. 2. **Kitex supports both PingPong APIs (non-streaming) and Streaming APIs in the same Service** - 1. Kitex server will automatically detect the protocol and route requests + 1. Kitex server will automatically detect the protocol and route requests 3. Unary over HTTP2 is not recommended due to performance loss; just use PingPong APIs 4. `streaming.mode` can appear at most once, otherwise kitex will report an error @@ -102,6 +107,7 @@ service TestService { #### Scaffold Generation For new projects, first initialize the project directory: + ```bash mkdir demo-project && cd demo-project @@ -110,12 +116,15 @@ go mod init $module ``` The use of Kitex is just the same as before, for example: + ```bash kitex -module $module -service demo-server api.thrift ``` + Note: For existing projects, you also need to regenerate the code and update the kitex version in your `go.mod`. Then run: + ```bash go mod tidy ``` @@ -125,6 +134,7 @@ go mod tidy ##### Create Stream Client \(for the caller side\) NOTE: + - You need to create **StreamClient** for calling a Streaming API - `streamclient.Option` \(not client.Option\) is used for creating a StreamClient - `streamcall.Option` \(not callopt.Option\) is used for a Streaming API call @@ -148,13 +158,15 @@ stream, err := streamClient.Echo(ctx, streamcall.WithHostPorts("127.0.0.1:8888") ##### Bidirectional Streaming API NOTE: + 1. The caller and callee should negotiate a way to finish the Stream, otherwise it may cause both parties to wait forever \(goroutine leak\). 2. The example shows full duplex mode \(Recv and Send are completely independent\). 1. The processing logic can be adjusted according to business needs, for example \(half-duplex mode\), the server always receives a message and processes it before sending the result to the client. ###### Server Handler -NOTE: +NOTE: + 1. Kitex will send the trailer frame \(which means the stream is closed\) after the method handler returns; there's no need for biz code to call stream.Close() manually. 2. Newly started goroutines should have panic-recover logic in business code 3. `io.EOF` returned by Recv call indicates that the client has finished sending @@ -164,13 +176,13 @@ Example code: [kitex-examples:thrift_streaming/handler.go#L34](https://github.co ###### Stream Client Note: + 1. Newly started goroutines should have panic-recover logic in business code 2. After the client finishes sending, it should promptly call stream.Close\(\) to inform the server. 3. A non-nil error \(including `io.EOF`\) returned by `Recv` indicates that the server has finished sending \(or encountered an error\) - 1. It's when Kitex records the `RPCFinish` event \(Tracer depends on this event\). - 2. If the client and server have another termination method, `streaming.FinishStream(stream, err)` should be called manually to record the RPCFinish event. - + 1. It's when Kitex records the `RPCFinish` event \(Tracer depends on this event\). + 2. If the client and server have another termination method, `streaming.FinishStream(stream, err)` should be called manually to record the RPCFinish event. Example code: [kitex-examples:thrift_streaming/client/demo_client.go#L119](https://github.com/cloudwego/kitex-examples/blob/v0.3.1/thrift_streaming/client/demo_client.go#L119) @@ -185,6 +197,7 @@ Example code: [kitex-examples:thrift_streaming/handler.go#L94](https://github.co ###### Stream Client Note: A non-nil error \(including `io.EOF`\) returned by `Recv` indicates that the server has finished sending \(or encountered an error\) + 1. It's when Kitex records the `RPCFinish` event \(Tracer depends on this event\). 2. If the client and server have another termination method, `streaming.FinishStream(stream, err)` should be called manually to record the RPCFinish event. @@ -202,7 +215,6 @@ Example code: [kitex-examples:thrift_streaming/handler.go#L82](https://github.co Example code: [kitex-examples:thrift_streaming/client/demo_client.go#L162](https://github.com/cloudwego/kitex-examples/blob/v0.3.1/thrift_streaming/client/demo_client.go#L162) - #### Options ##### StreamClient Options @@ -210,6 +222,7 @@ Example code: [kitex-examples:thrift_streaming/client/demo_client.go#L162](https Kitex distinguishes between **Client** \(for KitexThrift PingPong API\) and **StreamClient** \(for Streaming API\) in design, and requires **StreamClient** to use another set of Options \(of different types\) to avoid users specifying unsupported Options for StreamClient. NOTE: + - If a client/callopt Option does not have a corresponding streamclient/streamcall Option \(such as `WithRPCTimeout`\), it means that StreamClient does not support this capability. - If you think StreamClient should support this capability, you can [submit an issue to Kitex](https://github.com/cloudwego/kitex/issues). @@ -221,6 +234,7 @@ NOTE: - `WithSendMiddleware`、`WithSendMiddlewareBuilder`: details in "Recv/Send Middleware" Example code: + ```go import "github.com/cloudwego/kitex/client/streamclient" @@ -231,10 +245,12 @@ var streamClient = testservice.MustNewStreamClient( ``` ###### streamcall.Option + - Specified when creating Stream. - The priority is higher than the `streamclient.Option` with the same name \(if exists\). Example code: + ```go import "github.com/cloudwego/kitex/client/callopt/streamcall" @@ -246,7 +262,7 @@ stream, err := streamClient.Echo( ##### Server Options ->Due to the Server's support for automatic detection protocols, it can support both Streaming API and KitexThrift API, so it's impractical to use different Option types like StreamClient. +> Due to the Server's support for automatic detection protocols, it can support both Streaming API and KitexThrift API, so it's impractical to use different Option types like StreamClient. - Most [Server Option](/docs/kitex/tutorials/options/server_options/)\(s\) are applicable to Streaming APIs - **For uncertain options, validate before deploying to the production environment** @@ -268,16 +284,19 @@ stream, err := streamClient.Echo( ##### Connection Timeout It can be specified with the following options: + - `streamclient.WithConnectTimeout` -- `streamcall.WithConnectTimeout` \(higher priority\) +- `streamcall.WithConnectTimeout` \(higher priority\) ##### RPC Timeout \(not supported\) + There is no corresponding option. For the Streaming API, Kitex's Timeout Middleware will [do nothing but just call next](https://github.com/cloudwego/kitex/blob/v0.9.1/client/rpctimeout.go#L101). ##### Stream Timeout -To control the timeout for the whole stream, please create a context object with deadline by `context.WithTimeout` or `context.WithDeadline` , and create a stream with this context object. +To control the timeout for the whole stream, please create a context object with deadline by `context.WithTimeout` or `context.WithDeadline` , and create a stream with this context object. + - Kitex Client - A header `grpc-timeout` will be sent to the server - After deadline, Recv/Send will return an error `rpc error: code = 4 desc = context deadline exceeded` @@ -286,6 +305,7 @@ To control the timeout for the whole stream, please create a context object with - After deadline, Recv/Send will return an error `rpc error: code = 4 desc = context deadline exceeded` Example code: + ```go // inject deadline into context BEFORE creating a stream ctx, cancel := context.WithTimeout(context.Background(), time.Second) @@ -295,19 +315,22 @@ stream, err := cli.Echo(ctx) ``` ##### Recv/Send Timeout -Kitex provides a helper function `streaming.CallWithTimeout` for this. + +Kitex provides a helper function `streaming.CallWithTimeout` for this. ###### Client NOTE: + 1. Create a context with `cancel` **BEFORE creating a Stream** \(e.g. by WithCancel or WithTimeout\) 2. Set the `cancel` func as the 2nd param for `streaming.CallWithTimeout` - 1. Otherwise Send/Recv may block for a long timeout \(depending on the server side\) which may cause goroutine leak. +3. Otherwise Send/Recv may block for a long timeout \(depending on the server side\) which may cause goroutine leak. -3. The semantic of `stream.Close()` on the client side is `CloseSend`, informing the server that there will be no new messages (the server `Recv` call returns `io.EOF`), and does not close the receiving end, so it cannot be used as the cancel method. +4. The semantic of `stream.Close()` on the client side is `CloseSend`, informing the server that there will be no new messages (the server `Recv` call returns `io.EOF`), and does not close the receiving end, so it cannot be used as the cancel method. Example code: + ```go import "github.com/cloudwego/kitex/pkg/streaming" @@ -352,30 +375,36 @@ err = streaming.CallWithTimeout(time.Second, cancel, func() (errRecv error) { ``` #### CircuitBreak + Only supports the error rate fuse when **creating a connection \(stream\)**. No support for circuitbreaker on Recv/Send calls. - #### Retry \(Not Supported\) + Retry are not supported. #### Fallback \(Not Supported\) + Streaming API has no fallback support. #### LoadBalancer -- Load Balance is only supported when creating a Stream \(equivalent to creating a network connection\). + +- Load Balance is only supported when creating a Stream \(equivalent to creating a network connection\). - Subsequent Send/Recv calls will only be with the opposite end of the Stream - It's the user's responsibility to deal with uneven load caused by Recv/Send on certain streams. - Take file transmission as an example, one stream for a 1KB file \(only one Send needed\) and one stream for a 1GB file \(\) ##### Consistent Hash + Note: Since the Request obtained in a client middleware is always nil, your `keyFunc` cannot directly read the request. Workaround: -1. Before creating the Stream, calculate the hash value of your request and set it in ctx + +1. Before creating the Stream, calculate the hash value of your request and set it in ctx 2. Read the hash value in your `keyFunc` from ctx Example code: + ```go streamClient := testservice.MustNewStreamClient( "demo-server", @@ -399,7 +428,8 @@ ctx := context.WithKey(context.background(), "MY_HASH_KEY", keyFunc(request)) stream, err := streamClient.Echo(ctx, request) ``` -#### Server Limit \(QPS/Concurrency\) +#### Server Limit \(QPS/Concurrency\) + - Support limiting when creating a stream. - After creating a Stream, there are no restrictions on subsequent Recv/Send calls, which has to be implemented by the business itself. @@ -410,10 +440,11 @@ stream, err := streamClient.Echo(ctx, request) ##### Client Middleware NOTE: -- Client middleware only covers the **process of "creating a stream"** + +- Client middleware only covers the **process of "creating a stream"** - After creating the stream and returning to business code, all client middlewares are already executed - The request parameter is always nil /(even for Server Streaming API requests/) -- The response parameter is always of type *[streaming.Result](https://github.com/cloudwego/kitex/blob/v0.8.0/pkg/streaming/streaming.go#L67), containing the `Stream` finally returned to user code +- The response parameter is always of type \*[streaming.Result](https://github.com/cloudwego/kitex/blob/v0.8.0/pkg/streaming/streaming.go#L67), containing the `Stream` finally returned to user code - If there's a need, you can replace the Stream object with your own implementation using the [decorator pattern](https://zh.wikipedia.org/wiki/%E4%BF%AE%E9%A5%B0%E6%A8%A1%E5%BC%8F) - If the error returned is not nil, it means Kitex fails to create a stream - **Client Middleware can NOT obtain the message for Recv and Send calls.** @@ -421,6 +452,7 @@ NOTE: ###### Execution Flow Diagram Note: + - Below shows the flow of Bidirectional Streaming APIs (and Client Streaming APIs are similar) - But Server Streaming APIs are different: [Send and Close are called in kitex_gen \(generated code\)](https://github.com/cloudwego/kitex-examples/blob/v0.3.1/thrift_streaming/kitex_gen/echo/testservice/testservice.go#L336), before returning to user code. @@ -428,13 +460,14 @@ Note: ###### Request/Response types obtained -| | request | response | -|:----------------:|:-----------------:|:-----------------:| -| Bidirectional | interface{} = nil | *streaming.Result | -| Client Streaming | interface{} = nil | *streaming.Result | -| Server Streaming | interface{} = nil | *streaming.Result | +| | request | response | +| :--------------: | :---------------: | :----------------: | +| Bidirectional | interface{} = nil | \*streaming.Result | +| Client Streaming | interface{} = nil | \*streaming.Result | +| Server Streaming | interface{} = nil | \*streaming.Result | + +Note: -Note: 1. Request message is also not available in client middleware for Server Streaming API requests. Please use Client Send Middleware instead. 2. For Thrift Streaming Unary APIs, it's just the same as PingPong APIs. @@ -459,8 +492,9 @@ func clientMW(next endpoint.Endpoint) endpoint.Endpoint { ##### Server Middleware NOTE: + - The `next` method of Server Middleware covers the entire processing process of the server handler -- The request parameter is always of type *[streaming.Args](https://github.com/cloudwego/kitex/blob/v0.9.1/pkg/streaming/streaming.go#L70), containing the Stream finally returned to user code +- The request parameter is always of type \*[streaming.Args](https://github.com/cloudwego/kitex/blob/v0.9.1/pkg/streaming/streaming.go#L70), containing the Stream finally returned to user code - If there's a need, you can replace the Stream object with your own implementation using the [decorator pattern](https://zh.wikipedia.org/wiki/%E4%BF%AE%E9%A5%B0%E6%A8%A1%E5%BC%8F) - The response parameter is always nil \(even for Client Streaming API requests\) - If the error returned is not nil, it means some inner middleware or the handler fails. @@ -482,13 +516,14 @@ NOTE: ###### Request/Response field types obtained -| | request | response | -|:----------------:|:---------------:|:-----------------:| -| Bidirectional | *streaming.Args | interface{} = nil | -| Client Streaming | *streaming.Args | interface{} = nil | -| Server Streaming | *streaming.Args | interface{} = nil | +| | request | response | +| :--------------: | :--------------: | :---------------: | +| Bidirectional | \*streaming.Args | interface{} = nil | +| Client Streaming | \*streaming.Args | interface{} = nil | +| Server Streaming | \*streaming.Args | interface{} = nil | + +Note: -Note: 1. The client request message is also not available in server middleware for Server Streaming API requests. Please use Server Recv Middleware instead. 2. For Thrift Streaming Unary APIs, it's just the same as PingPong APIs. @@ -509,6 +544,7 @@ func serverMW(next endpoint.Endpoint) endpoint.Endpoint { } } ``` + Note: for Thrift Streaming Unary APIs, it's just the same as PingPong APIs. #### Recv/Send Middleware @@ -521,7 +557,7 @@ Messages can be intercepted with Recv/Send Middleware. NOTE: in Recv Middleware, **`next` should be called before reading the message** -###### StreamClient +###### StreamClient NOTE: for client, the message type for a `Recv` call should be the API's **response** type defined in IDL @@ -546,6 +582,7 @@ var streamClient = testservice.MustNewStreamClient( }), ) ``` + ###### Server NOTE: for server, the message type for a `Recv` call should be the API's **request** type defined in IDL @@ -562,6 +599,7 @@ svr := test.NewServer(new(TestServiceImpl), }), ) ``` + ##### Send Middleware ###### StreamClient @@ -589,6 +627,7 @@ var streamClient = testservice.MustNewStreamClient( }), ) ``` + ###### Server NOTE: for server, the message type for a `Send` call should be the API's **response** type defined in IDL @@ -611,6 +650,7 @@ svr := test.NewServer(new(TestServiceImpl), By injecting keys into the ctx used to create the stream, we can share data between middlewares. Kitex provides a set of helper functions to inject a `sync.Map` for sharing data between middlewares: + - [contextmap.WithContextMap(ctx)](https://github.com/cloudwego/kitex/blob/v0.9.1/pkg/utils/contextmap/contextmap.go#L32C6-L32C20) - [contextmap.GetContextMap(ctx)](https://github.com/cloudwego/kitex/blob/v0.9.1/pkg/utils/contextmap/contextmap.go#L37) @@ -655,11 +695,13 @@ streamClient = testservice.MustNewStreamClient( The server side is different from the client side. Before entering a server middleware, the stream has already been created, so it's impossible to inject a key inside a server middleware. However, it can be achieved in the following way: + - Specify a `MetaHandler` with `server.WithMetaHandler` Option - This `MetaHandler` should implement the interface `StreamingMetaHandler` - In the function `OnReadStream`, inject `sync.Map` into ctx, and return the new ctx object. Kitex provides a customMetaHandler making it quite easy to add a key to the context before creating a stream. You only need to specify the following option when initializing a server: + ```go server.WithMetaHandler(remote.NewCustomMetaHandler(remote.WithOnReadStream( func(ctx context.Context) (context.Context, error) { @@ -667,7 +709,9 @@ server.WithMetaHandler(remote.NewCustomMetaHandler(remote.WithOnReadStream( }, ))) ``` + Note: + 1. Full example code in: [kitex-tests: TestCustomMetaHandler](https://github.com/cloudwego/kitex-tests/blob/main/thrift_streaming/thrift_test.go#L1090) 2. If you don't want to use the RC tag for now, you may implement your MetaHandler according to [customMetaHandler](https://github.com/cloudwego/kitex/blob/v0.9.1/pkg/remote/custom_meta_handler.go#L29) @@ -676,6 +720,7 @@ Note: Please refer to the "Kitex gRPC Metadata" section in [CloudWeGo - Kitex - Metainfo](/docs/kitex/tutorials/advanced-feature/metainfo/#kitex-grpc-metadata). NOTE + - metainfo - Keys with lowercase letters or hyphen will be dropped, e.g. "Hello", "HELLO-WORLD" - metadata @@ -683,7 +728,6 @@ NOTE - header & trailer - Keys with capital letters will cause errors on the client side - ### Observability #### Basic Events: RPCStart & RPCFinish @@ -698,6 +742,7 @@ Kitex users can add customized Tracers to deal with those events in the `Finish( If at least one Tracer implements the interface [rpcinfo.StreamEventReporter](https://github.com/cloudwego/kitex/blob/v0.9.1/pkg/rpcinfo/tracer.go#L31), Kitex will inject the corresponding Recv/Send middleware for to call the tracer's `ReportStreamEvent` after the execution of each Recv/Send call. The message size of current Recv/Send can be obtained by (note: do not call it in another goroutine, otherwise you may get the size of some other call): + - `ri.Stats().LastSendSize()` - `ri.Stats().LastRecvSize()` @@ -713,11 +758,12 @@ You can find an example here: [kitex-tests: testTracer](https://github.com/cloud GRPC/HTTP2 is implemented with a "local buffer", where Send/Recv operations are performed. Therefore you should be aware of: + 1. "Send returns nil" only means the message is appended to the local buffer, which **DOES NOT** indicate the message is received by the opposite end; 2. The time consumed by Send/Recv operations differs significantly with the "Latency" of a Ping-Pong API: - 1. If the Recv call frequency at the opposite end is higher, then the local Send will usually return immediately \(the buffer is always free\). - 2. If the Recv call frequency of the opposite end is lower, the local Send may be blocked for some time \(waiting for the other end to consume and free up the buffer\). - 3. If there is message(s) available in the buffer, the Recv call will return immediately, otherwise you need to wait for the other end's Send. + 1. If the Recv call frequency at the opposite end is higher, then the local Send will usually return immediately \(the buffer is always free\). + 2. If the Recv call frequency of the opposite end is lower, the local Send may be blocked for some time \(waiting for the other end to consume and free up the buffer\). + 3. If there is message(s) available in the buffer, the Recv call will return immediately, otherwise you need to wait for the other end's Send. #### Client/Server Middleware unable to get the Request/Response @@ -725,7 +771,7 @@ It's BY DESIGN. Although for Client Streaming/Server Streaming requests, it seems to have a Request/Response just like the PingPong API, the underlying implementation is completely different, and they cannot be read in Client/Server Middleware. Please use Recv/Send Middleware to process messages on the stream. -#### RPCFinish: client for Server/Bidirectional API should call Recv until receiving a non-nil error +#### RPCFinish: client for Server/Bidirectional API should call Recv until receiving a non-nil error - For Server/Bidirectional Streaming APIs: Kitex Client will not record the RPCFinish event until `Recv()` receives a non-nil error \(`io.EOF` or other errors\). - If you wish to finish stream early, please remember to manually call `streaming.FinishStream(stream, err)` to propagate the RPCFinish event. @@ -781,6 +827,7 @@ if someCondition { ``` Note: + - For Server Streaming API requests: before business code gets the stream returning by a client call, the sending stream is [already closed in the generated code](https://github.com/cloudwego/kitex-examples/blob/v0.3.1/thrift_streaming/kitex_gen/echo/testservice/testservice.go#L336); therefore, the client is unable to send new messages to the server and what it can do is to end the connection prematurely to inform the server - Since `st.Recv()` does not receive a non-nil error, `streaming.FinishStream(st, err)` should be called manually to generate the stream's `RPCFinish` event. -- For Bidirectional Streaming APIs, this way is also applicable, but it's better to call the `st.Close()` manually or to send a previously negotiated message to the server. Don't forget to call `streaming.FinishStream` in either case. \ No newline at end of file +- For Bidirectional Streaming APIs, this way is also applicable, but it's better to call the `st.Close()` manually or to send a previously negotiated message to the server. Don't forget to call `streaming.FinishStream` in either case. diff --git a/content/en/docs/kitex/Tutorials/basic-feature/visit_directly.md b/content/en/docs/kitex/Tutorials/basic-feature/visit_directly.md index 6f58833c07..484e3e2bba 100644 --- a/content/en/docs/kitex/Tutorials/basic-feature/visit_directly.md +++ b/content/en/docs/kitex/Tutorials/basic-feature/visit_directly.md @@ -7,7 +7,9 @@ description: Kitex can opt for direct access without service discovery when the --- ## Specify RPC Host and Port + You can use `callopt.WithHostPort` to specify host and port, supports two parameters: + - Normal IP address, in the form of `host:port`, support `IPv6` - Sock file address, communicating with UDS (Unix Domain Socket) diff --git a/content/en/docs/kitex/Tutorials/basic-feature/warming_up.md b/content/en/docs/kitex/Tutorials/basic-feature/warming_up.md index 43bf20a5a5..5866bc9c12 100644 --- a/content/en/docs/kitex/Tutorials/basic-feature/warming_up.md +++ b/content/en/docs/kitex/Tutorials/basic-feature/warming_up.md @@ -57,8 +57,7 @@ type PoolOption struct { ### Common Usage -#### Perform Service Discovery when creating client - +#### Perform Service Discovery when creating client ```go cli, err := myservice.NewClient(psm, client.WithWarmingUp(&warmup.ClientOption{ diff --git a/content/en/docs/kitex/Tutorials/code-gen/_index.md b/content/en/docs/kitex/Tutorials/code-gen/_index.md index a77666d6fa..6aca1204aa 100644 --- a/content/en/docs/kitex/Tutorials/code-gen/_index.md +++ b/content/en/docs/kitex/Tutorials/code-gen/_index.md @@ -4,5 +4,4 @@ linkTitle: "Code Generation" weight: 5 date: 2021-08-31 description: > - --- diff --git a/content/en/docs/kitex/Tutorials/code-gen/idl_trimmer.md b/content/en/docs/kitex/Tutorials/code-gen/idl_trimmer.md index 43bd21f82e..e5287e74ac 100644 --- a/content/en/docs/kitex/Tutorials/code-gen/idl_trimmer.md +++ b/content/en/docs/kitex/Tutorials/code-gen/idl_trimmer.md @@ -7,6 +7,7 @@ description: "Use the IDL trimming tool to remove unnecessary IDL definitions" --- ## Introduction + [Thriftgo](https://github.com/cloudwego/thriftgo) is a Thrift IDL parser and code generator implemented in Go. It supports comprehensive Thrift IDL syntax and semantic checks. Compared to the official Golang code generated by Apache Thrift, Thriftgo has made some bug fixes and supports plugin mechanisms, allowing users to customize the generated code according to their needs. The code generation tool for Kitex is one of the plugin implementations of Thriftgo. Some IDL repositories may accumulate unrelated content over time due to lack of timely maintenance. With version iterations, the amount of unrelated content increases, resulting in large generated Golang code repositories and reduced readability of the IDL. It may also include excessive IDL references, resulting in irrelevant structures being included in the generated code, leading to oversized code or exceptions during the code generation process. These issues frequently occur in complex project practices and may hinder the development workflow. @@ -16,29 +17,36 @@ Thriftgo provides IDL trimming functionality starting from version v0.3.1+. This This feature can be used separately using the Trimmer tool provided under the Thriftgo project, or it can be used in conjunction with the Thriftgo/Kitex command line to filter out unused content during code generation. ## Trimming Principle + - Traverse all services included in the given IDL file and mark all struct structures directly or indirectly referenced by services and methods as "used". - Scan all IDLs directly or indirectly referenced by this project. For all struct structures, if they are not marked as "used", they will be pruned. - Since businesses often use IDL to introduce enums and constants, the tool does not trim typedefs, enums, and constants in the IDL. - The trimmed result is output as an IDL file with the .thrift extension or as generated Golang code. The following is an illustration of the IDL files before trimming. -![img](/img/docs/idl_trimmer_process1.jpg) +![img](/img/docs/idl_trimmer_process1.jpg) After using the trimming tool, it will traverse all structures based on service A in IDL A and remove unused struct structures. The final output is as follows. ![img](/img/docs/idl_trimmer_process2.jpg) ## Using the Trimmer Tool -The Trimmer tool supports processing thrift IDL files and outputs the trimmed results as thrift IDL files. -Install the Trimmer tool: +The Trimmer tool supports processing thrift IDL files and outputs the trimmed results as thrift IDL files. + +Install the Trimmer tool: + ```bash go install github.com/cloudwego/thriftgo/tool/trimmer@latest ``` + Check the version/verify the installation: + ```bash trimmer -version ``` + Usage format: + ```bash trimmer [options] file @@ -49,26 +57,37 @@ Options: -r, --recurse [dir] Specify a root directory, copy its directory structure to the output directory, and recursively output the specified IDL and its referenced IDLs to the corresponding locations. If -o is specified, it must be a directory. -m, --method [service.method] Specify one or more methods to be retained for trimming ``` + ### Single File Processing + When you want to trim a single IDL file, you can execute the following command: + ```bash trimmer sample.thrift ``` + After successful execution, the location of the trimmed IDL file will be output, and you will see the following prompt: -`success, dump to example_trimmed.thrift` +`success, dump to example_trimmed.thrift` By default, the trimmed IDL is named with the original name + "trimmed" suffix. If you want to output the trimmed IDL to a specific directory or rename it, you can use the -o parameter: + ```bash trimmer -o abc/my_sample.thrift sample.thrift ``` + Note that due to the fact that IDL definitions themselves do not record indentation, line breaks, and order, the field order in the output new IDL file may differ from the original version. + ### Recursive Trimming -If you want to trim a specific IDL and simultaneously trim and output the related IDLs it references, you can use the -r parameter: + +If you want to trim a specific IDL and simultaneously trim and output the related IDLs it references, you can use the -r parameter: + ```bash trimmer -r test_cases/ test_cases/my_idl/a.thrift ``` -Note that when using -r, you need to specify the IDL file directory after the -r parameter. The tool will search for dependent IDLs in this folder, trim them, and maintain the directory structure in the output (based on the dependency of the specified IDL). -The default output location is the "trimmed_idl" folder. You can set the output folder name using -o. The directory structure after output is as follows: + +Note that when using -r, you need to specify the IDL file directory after the -r parameter. The tool will search for dependent IDLs in this folder, trim them, and maintain the directory structure in the output (based on the dependency of the specified IDL). +The default output location is the "trimmed_idl" folder. You can set the output folder name using -o. The directory structure after output is as follows: + ``` . ├── test_cases // the original folder @@ -81,55 +100,75 @@ The default output location is the "trimmed_idl" folder. You can set the output │ └── a.thrift └── c.thrift ``` + ### Specifying Methods to Retain + In the "Trimming Principle" section, it was mentioned that by default, the Trimmer tool searches for all methods of all services to trim the structures. If you want to refine the trimming logic to specific methods or multiple methods, you can use the -m parameter and specify them in the format `[service_name.method_name]`. + ```bash trimmer -m MyService.MethodA -m MyService.MethodB example.thrift` ``` + When there is only one service in the target IDL, you can omit the service name: + ```bash trimmer -m MethodA -m MethodB example.thrift ``` + After execution, the other services and methods will be trimmed, and only the specified methods and their dependent structures will be retained. In Thriftgo v0.3.3 (not yet released, but can be obtained from the latest commit), the ability to specify methods for trimming supports regular expression matching. Users can construct regular expressions to match the method names in the format `[serviceName].[methodName]` and precisely specify one or more methods. For example: + ```bash trimmer -m 'Employee.*\..*' test_cases/sample1.thrift ``` + This can match all methods under the service starting with "Employee". (Note: "." has special meaning in regular expressions, so it's best to use "\." to match). You can also use some Perl-style expressions for advanced trimming operations. For example: + ```bash trimmer -m '^(?!EmployeeService.getEmployee).*$' test_cases/sample1.thrift ``` + This can match all methods except for `EmployeeService.getEmployee`. By executing this command, you can remove this method and its dependencies from the IDL (assuming other methods have no dependencies). ### Protecting Structures from Trimming + For specific development needs, you may want the trimming tool to retain certain structures, allowing you to utilize the corresponding generated code. You can annotate the struct, union, or exception with the `@preserve` comment above it to indicate that it should be preserved during trimming. It will be retained unconditionally during trimming. The `@preserve` comment can coexist with other comments, but make sure that the `@preserve` comment is on a separate line. For example: + ```thrift // @preserve struct Useless{ } ``` + Even if this structure is not referenced, it will still be preserved after trimming. This feature is enabled by default and can be disabled by setting the -p or -preserve parameter to false. For example: + ```bash trimmer -p false sample.thrift ``` + In this case, the Trimmer tool will disregard the `@preserve` comment and proceed with trimming. + ## Integration with Kitex Tool + The Trimmer feature can also be integrated directly into the code generation process of Thriftgo/Kitex. However, make sure that the Thriftgo version is not lower than v0.3.1. Taking Kitex as an example, you can add the `-thrift trim_idl` parameter when using it, like this: + ```bash kitex -module xx -thrift trim_idl xxx.thrift` ``` + When using this parameter, the command line will output an additional prompt: -`[WARN] You Are Using IDL Trimmer` +`[WARN] You Are Using IDL Trimmer` During code generation, the source IDL will be trimmed, and the resulting generated Golang code will not contain unused structures. ## Configuration Using YAML + To facilitate configuration of the trimmer tool parameters through Kitex/Thriftgo integration, Thriftgo v0.3.3 (not yet released, but can be obtained from the latest commit) provides support for a YAML configuration file for the trimmer tool. When integrating with Kitex/Thriftgo or using the trimmer tool directly, the trimmer will automatically scan and apply the trim_config.yaml configuration file located in the current execution directory (os.Getwd()). When using the YAML configuration file, you will receive a similar prompt: @@ -138,17 +177,20 @@ When using the YAML configuration file, you will receive a similar prompt: In addition to providing a configuration parameter method for integrating with Kitex/Thriftgo, IDL authors can use the YAML configuration file to define the content to be preserved during trimming, which can serve as a template for batch trimming or be shared with others. ### YAML Configuration Example: + ```yaml methods: -- "TestService.func1" -- "TestService.func3" + - "TestService.func1" + - "TestService.func3" preserve: true preserved_structs: -- "usefulStruct" + - "usefulStruct" ``` + ### Configuration Format + Currently, the following options can be configured using YAML: + - methods: An array of strings, equivalent to the -m parameter, indicating the methods to be preserved during trimming. Refer to the "Specifying Methods to Retain" section for the format and functionality. If the -m parameter is specified in the command line, it will override the YAML configuration. - preserve: A boolean value, equivalent to the -p parameter, set to false to disable the functionality of preserving structures from being trimmed, such as using the @preserve comment. The default value is true. If the -p parameter is specified in the command line, it will override the YAML configuration. - preserved_structs: An array of strings, indicating the names of structures to be preserved. If preserve or the -p parameter in the command line is set to true, the trimmer will unconditionally preserve the specified structures. This can be used for struct, union, and exception structures. - diff --git a/content/en/docs/kitex/Tutorials/code-gen/template_extension.md b/content/en/docs/kitex/Tutorials/code-gen/template_extension.md index e6c0e62764..d698138f9f 100644 --- a/content/en/docs/kitex/Tutorials/code-gen/template_extension.md +++ b/content/en/docs/kitex/Tutorials/code-gen/template_extension.md @@ -32,36 +32,34 @@ Assume we have an extensions.yaml file: ```yaml --- dependencies: - example.com/my/pkg: pkg + example.com/my/pkg: pkg extend_client: - import_paths: - - example.com/my/pkg - extend_option: - options = append(options, client.WithSuite(pkg.MyClientSuite())) - extend_file: |- - func Hello() { - println("hello world") - } + import_paths: + - example.com/my/pkg + extend_option: options = append(options, client.WithSuite(pkg.MyClientSuite())) + extend_file: |- + func Hello() { + println("hello world") + } extend_server: - import_paths: - - example.com/my/pkg - extend_option: - options = append(options, server.WithSuite(pkg.MyServerSuite())) - extend_file: |- - func Hello() { - println("hello world") - } + import_paths: + - example.com/my/pkg + extend_option: options = append(options, server.WithSuite(pkg.MyServerSuite())) + extend_file: |- + func Hello() { + println("hello world") + } ``` - **dependencies**: Defines a set of packages that may be used in the template and the names they should be aliased as. - **extend_client**: Customization for client.go - - **import_paths**: Declare the package list that the code injected into client.go needs to import. Those packages must be declared in the **dependencies**. + - **import_paths**: Declare the package list that the code injected into client.go needs to import. Those packages must be declared in the **dependencies**. - - **extend_option**: The code snippet will be injected into the `NewClient` function, where the default options are constructed. Thus, you can inject your own suite option. + - **extend_option**: The code snippet will be injected into the `NewClient` function, where the default options are constructed. Thus, you can inject your own suite option. - - **extend_file**: The code snippet will be directly appended to client.go. You can add extra functions or constants here. + - **extend_file**: The code snippet will be directly appended to client.go. You can add extra functions or constants here. - **extend_server** field works like the **extend_client** field. diff --git a/content/en/docs/kitex/Tutorials/code-gen/validator.md b/content/en/docs/kitex/Tutorials/code-gen/validator.md index 186e187696..fe718f9ede 100644 --- a/content/en/docs/kitex/Tutorials/code-gen/validator.md +++ b/content/en/docs/kitex/Tutorials/code-gen/validator.md @@ -5,8 +5,6 @@ weight: 3 description: > --- - - ## Overview Validator is a thrift plugin that supports struct validation. @@ -40,9 +38,9 @@ struct Response { ## Installation -Before using the Validator plugin, you should install it first. +Before using the Validator plugin, you should install it first. -Otherwise, an error message will be displayed stating that the `thrift-gen-validator` executable file cannot be found (`exec: "thrift-gen-validator": executable file not found in $PATH`). +Otherwise, an error message will be displayed stating that the `thrift-gen-validator` executable file cannot be found (`exec: "thrift-gen-validator": executable file not found in $PATH`). If you have already installed Golang and Kitex command-line tools, please run the following command to install the `thrift-gen-validator` plugin: @@ -50,12 +48,12 @@ If you have already installed Golang and Kitex command-line tools, please run th $ go install github.com/cloudwego/thrift-gen-validator@latest ``` -After executing `go install`, the compiled `thrift-gen-validator` binary file will be installed under `$GOPATH/bin`. +After executing `go install`, the compiled `thrift-gen-validator` binary file will be installed under `$GOPATH/bin`. You can run the following command to verify that the installation was successful. ```shell -$ cd $(go env GOPATH)/bin +$ cd $(go env GOPATH)/bin $ ls go1.20.1 goimports hz thrift-gen-validator godotenv golangci-lint kitex thriftgo @@ -82,7 +80,7 @@ struct Request { } ``` -When generating kitex code, add `--thrift-plugin validator` to generate the validator code. +When generating kitex code, add `--thrift-plugin validator` to generate the validator code. ``` kitex --thrift-plugin validator -service a.b.c hello.thrift @@ -249,7 +247,7 @@ struct OuterRequest { The prefix '$' represents a reference to a variable, which can be used for **cross-field verification**: -1. $x represents a variable named x, the variable name is \[a-zA-Z0-9_]\, and its scope rule is **current structure**. +1. $x represents a variable named x, the variable name is \[a-zA-Z0-9\_]\, and its scope rule is **current structure**. 2. $ represents the current field where the validator is located. ```Thrift diff --git a/content/en/docs/kitex/Tutorials/framework-exten/_index.md b/content/en/docs/kitex/Tutorials/framework-exten/_index.md index 2c77307eb8..97b72774b6 100644 --- a/content/en/docs/kitex/Tutorials/framework-exten/_index.md +++ b/content/en/docs/kitex/Tutorials/framework-exten/_index.md @@ -4,7 +4,6 @@ linkTitle: "Framework Extension" weight: 6 date: 2021-08-31 description: > - --- ## Overview diff --git a/content/en/docs/kitex/Tutorials/framework-exten/codec.md b/content/en/docs/kitex/Tutorials/framework-exten/codec.md index 7165d20592..64424e72cb 100644 --- a/content/en/docs/kitex/Tutorials/framework-exten/codec.md +++ b/content/en/docs/kitex/Tutorials/framework-exten/codec.md @@ -9,7 +9,7 @@ description: > Kitex supports extending protocols, including overall Codec and Payloadcodec. Generally, RPC protocol includes application layer transport protocol and payload protocol. For example, HTTP/HTTP2 belong to application layer transport protocol, payloads with different formats and protocols can be carried over HTTP/HTTP2. -Kitex supports built-in TTHeader as transport protocol, and supports Thrift, Kitex Protobuf, gRPC protocol as payload. In addition, Kitex integrates [netpoll-http2](https://github.com/cloudwego/netpoll-http2) to support HTTP2. At present, it is mainly used for gRPC, Thrift over HTTP2 is considered to support in the future. +Kitex supports built-in TTHeader as transport protocol, and supports Thrift, Kitex Protobuf, gRPC protocol as payload. In addition, Kitex integrates [netpoll-http2](https://github.com/cloudwego/netpoll-http2) to support HTTP2. At present, it is mainly used for gRPC, Thrift over HTTP2 is considered to support in the future. The definition of TTHeader transport protocol as follows, service information can be transparently transmitted through the TTHeader to do service governance. @@ -117,7 +117,7 @@ cli, err := xxxservice.NewClient(targetService, client.WithCodec(yourCodec)) ``` -- Specify PayloadCodec +- Specify PayloadCodec option: `WithPayloadCodec` ```go diff --git a/content/en/docs/kitex/Tutorials/framework-exten/diagnosis.md b/content/en/docs/kitex/Tutorials/framework-exten/diagnosis.md index abb2c4d14a..7eeadb90f2 100644 --- a/content/en/docs/kitex/Tutorials/framework-exten/diagnosis.md +++ b/content/en/docs/kitex/Tutorials/framework-exten/diagnosis.md @@ -57,8 +57,6 @@ const ( ) ``` - - ## Integrate into Kitex Specify your own diagnostic service through option: `WithDiagnosisService`. @@ -70,4 +68,3 @@ svr := xxxservice.NewServer(handler, server.WithDiagnosisService(yourDiagnosisSe // client side cli, err := xxxservice.NewClient(targetService, client.WithDiagnosisService(yourDiagnosisService)) ``` - diff --git a/content/en/docs/kitex/Tutorials/framework-exten/middleware.md b/content/en/docs/kitex/Tutorials/framework-exten/middleware.md index 40c5f01e56..159e83cf10 100644 --- a/content/en/docs/kitex/Tutorials/framework-exten/middleware.md +++ b/content/en/docs/kitex/Tutorials/framework-exten/middleware.md @@ -6,11 +6,13 @@ description: > --- ## Middleware + Middleware is a relatively low level of extension. Most of the Kitex-based extension and secondary development functions are based on middleware to achieve. Kitex's Middleware is defined in `pkg/endpoint/endpoint.go`, the most important of which are two types: 1. `Endpoint` is a function that accepts ctx, req, resp and returns err. Please refer to the following "Example" code. 2. Middleware (hereinafter referred to as MW) is also a function that receives and returns an Endpoint. + ```go type Middleware func(Endpoint) Endpoint ``` @@ -57,6 +59,7 @@ Middleware can be injected into ctx using `ctx = client.WithContextMiddlewares(c Note: Context Middleware executes before middleware set by `client.WithMiddleware()`. ### Server Middleware + #### How To Use 1. `server.WithMiddleware` adds Middleware to the current server. @@ -74,8 +77,11 @@ Note: Context Middleware executes before middleware set by `client.WithMiddlewar 3. Error handler set by `client.WithErrorHandler` The above can be seen in [server.go](https://github.com/cloudwego/kitex/blob/develop/server/server.go) + ### Example + We can use the following example to see how to use Middleware. + #### Request/Reponse If we need to print out the request content before the request, and then print out the response content after the request, we can write the following middleware (For the service which include streaming call, see the gRPC middleware below): @@ -113,13 +119,16 @@ func ExampleMiddleware(next endpoint.Endpoint) endpoint.Endpoint { } } ``` + The provided example is for illustrative purposes, and it is indeed important to exercise caution when implementing such logging practices in a production environment. Logging every request and response indiscriminately can indeed have performance implications, especially when dealing with large response bodies. ### Precautions + 1. If RPCInfo is used in custom middleware, be aware that RPCInfo will be recycled after the rpc ends, so if you use goroutine operation RPCInfo in middleware, there will be issues . Please avoid such operations . 2. Middleware is a chained call, if you use `result. SetSuccess()` or some other way to modify the response in any middleware, the upstream middlewares will receive the modified response. ### gRPC Middleware + As we all know, in addition to Thrift, Kitex also supports the protobuf and gRPC encoding/decoding protocols. In the case of protobuf, it refers to using protobuf exclusively to define the payload format, and the service definition only includes unary methods. However, if streaming methods are introduced, Kitex will use the gRPC protocol for encoding/decoding and communication. For services using protobuf (unary only), the development of middleware remains consistent with the previous context, as the design of both is identical. @@ -148,7 +157,9 @@ func newWrappedStream(s streaming.Stream) streaming.Stream { return &wrappedStream{s} } ``` + Then, within the middleware, insert the wrapped streaming.Stream object at specific invocation points. + ```go import "github.com/cloudwego/kitex/pkg/streaming" @@ -176,19 +187,23 @@ func DemoGRPCMiddleware(next endpoint.Endpoint) endpoint.Endpoint { } } ``` + Explanation of the request/response parameter types obtained within the Kitex middleware in different scenarios of gRPC: -| Scenario | Request Type | Response Type | -|----------------------------------|---------------------------|-----------------------------| -| Kitex-gRPC Server Unary/Streaming | *streaming.Args | nil | -| Kitex-gRPC Client Unary | *xxxservice.XXXMethodArgs | *xxxservice.XXXMethodResult | -| Kitex-gRPC Client Streaming | nil | *streaming.Result | +| Scenario | Request Type | Response Type | +| --------------------------------- | -------------------------- | ---------------------------- | +| Kitex-gRPC Server Unary/Streaming | \*streaming.Args | nil | +| Kitex-gRPC Client Unary | \*xxxservice.XXXMethodArgs | \*xxxservice.XXXMethodResult | +| Kitex-gRPC Client Streaming | nil | \*streaming.Result | ## Summary -Middleware is indeed a lower-level implementation of extensions, typically used to inject simple code containing specific functionalities. However, in complex scenarios, single middleware may not be sufficient to meet the business requirements. In such cases, a more comprehensive approach is needed, which involves assembling multiple middlewares or options into a complete middleware layer. Users can develop this requirement based on suites, refer to [Suite Extend](/zh/docs/kitex/tutorials/framework-exten/suite/) + +Middleware is indeed a lower-level implementation of extensions, typically used to inject simple code containing specific functionalities. However, in complex scenarios, single middleware may not be sufficient to meet the business requirements. In such cases, a more comprehensive approach is needed, which involves assembling multiple middlewares or options into a complete middleware layer. Users can develop this requirement based on suites, refer to [Suite Extend](/zh/docs/kitex/tutorials/framework-exten/suite/) ## FAQ + ### How to recover handler panic in middleware + Question: A handler who wanted to recover their own business in middleware threw a panic and found that the panic had already been recovered by the framework. @@ -206,6 +221,7 @@ func TestServerMiddleware(next endpoint.Endpoint) endpoint.Endpoint { } } ``` + ### How to get the real Request/Response in Middleware? Due to implementation needs, the req and resp passed in middlewares are not the req and resp passed by the real user, but an object wrapped by Kitex, specifically a structure similar to the following. @@ -264,6 +280,7 @@ func (p *${XMethod}Result) GetSuccess() *${XResponse} { The above generated code can be seen in kitex_gen directory. Therefore, there are three solutions for the business side to obtain the real req and resp: + 1. If you can determine which method is being called and the type of req used, you can directly obtain the specific Args type through type assertion, and then obtain the real req through the GetReq method. 2. For thrift generated code, by asserting `GetFirstArgument` or `GetResult` , obtain `interface{}`, and then do type assertion to the real req or resp (Note: Since the returned `interface{}` contains a type, judging `interface{}` nil cannot intercept the case where req/resp itself is a null pointer, so we need to judge whether the asserted req/resp is a null pointer again); 3. Obtain the real request/response body through reflection method, refer to the code: @@ -278,6 +295,5 @@ var ExampleMW endpoint.Middleware = func(next endpoint.Endpoint) endpoint.Endpoi log.Infof(ctx, "response: %T", respV.Interface()) return err } -} +} ``` - diff --git a/content/en/docs/kitex/Tutorials/framework-exten/registry.md b/content/en/docs/kitex/Tutorials/framework-exten/registry.md index b9c184301f..6a6c69492f 100644 --- a/content/en/docs/kitex/Tutorials/framework-exten/registry.md +++ b/content/en/docs/kitex/Tutorials/framework-exten/registry.md @@ -8,6 +8,7 @@ description: > Kitex supports user-defined registration module. Users can extend and integrate other registration centers by themselves. This extension is defined under pkg/registry. ## Extension API and Definition of Info Struct + - Extension API ```go @@ -19,7 +20,8 @@ type Registry interface { ``` - Definition of Info Struct -Kitex defines some registration information. Users can also expand the registration information into tags as needed. + Kitex defines some registration information. Users can also expand the registration information into tags as needed. + ```go // Info is used for registry. // The fields are just suggested, which is used depends on design. @@ -41,6 +43,7 @@ type Info struct { ``` ## Integrate into Kitex + Specify your own registration module and customized registration information through `option`. Note that registration requires service information, which is also specified through option. - Specify Server Info @@ -72,5 +75,3 @@ Specify your own registration module and customized registration information thr ```go svr := xxxservice.NewServer(handler, server.WithRegistry(yourRegistry), server.WithRegistryInfo(yourRegistryInfo)) ``` - - diff --git a/content/en/docs/kitex/Tutorials/framework-exten/service_discovery.md b/content/en/docs/kitex/Tutorials/framework-exten/service_discovery.md index 9afa581120..ce7c1d49ec 100644 --- a/content/en/docs/kitex/Tutorials/framework-exten/service_discovery.md +++ b/content/en/docs/kitex/Tutorials/framework-exten/service_discovery.md @@ -39,9 +39,9 @@ type Change struct { `Resolver` interface detail: - `Resolve`: as the core method of `Resolver`, it obtains the service discovery result from target key -- `Target`: it resolves the unique target endpoint that from the downstream endpoints provided by `Resolve`, and the result will be used as the unique key of the cache -- `Diff`: it is used to compare the discovery results with the last time. The differences in results are used to notify other components, such as [loadbalancer](../../service-governance/loadbalance) and circuitbreaker, etc -- `Name`: it is used to specify a unique name for `Resolver`, and will use it to cache and reuse `Resolver` +- `Target`: it resolves the unique target endpoint that from the downstream endpoints provided by `Resolve`, and the result will be used as the unique key of the cache +- `Diff`: it is used to compare the discovery results with the last time. The differences in results are used to notify other components, such as [loadbalancer](../../service-governance/loadbalance) and circuitbreaker, etc +- `Name`: it is used to specify a unique name for `Resolver`, and will use it to cache and reuse `Resolver` ## Usage Example @@ -62,5 +62,4 @@ func main() { ## Attention -To improve performance, Kitex reusing `Resolver`, so the `Resolver` method implementation must be concurrent security. - +To improve performance, Kitex reusing `Resolver`, so the `Resolver` method implementation must be concurrent security. diff --git a/content/en/docs/kitex/Tutorials/framework-exten/suite.md b/content/en/docs/kitex/Tutorials/framework-exten/suite.md index f716a05184..6fbec026a1 100644 --- a/content/en/docs/kitex/Tutorials/framework-exten/suite.md +++ b/content/en/docs/kitex/Tutorials/framework-exten/suite.md @@ -6,12 +6,15 @@ description: > --- ## Introduction + Suite is a high-level abstraction for extensions, which can be understood as a combination and encapsulation of Option and Middleware. In the process of expansion, we need to remember two principles: + 1. Suite can only be set when initializing Server and Client, and dynamic modification is not allowed. 2. The suite is executed in the order of the settings. For the client, it executes in the order of the settings, while for the server, it is the opposite. The definition of Suite is as follows: + ```golang type Suite interface { Options() []Option @@ -21,6 +24,7 @@ type Suite interface { Both Server and Client use the `WithSuite` method to enable the new suite. ## Example + ```golang type mockSuite struct{ config *Config @@ -40,4 +44,5 @@ func (m *mockSuite) Options() []Option { The above code defines a simple client suite implementation, and we can use `client.WithSuite(&mockSuite{})` in the code to use all middleware/options encapsulated by this suite. ## Summary + Suite is a higher-level combination and encapsulation. It is highly recommended for third-party developers to provide Kitex extensions to the outside world based on Suite. Suite allows dynamic injection of values during creation or dynamically specifying values in its middleware based on certain runtime values. This makes it more convenient for users and third-party developers, eliminating the need for reliance on global variables and enabling the possibility of using different configurations for each client. diff --git a/content/en/docs/kitex/Tutorials/framework-exten/trans_pipeline.md b/content/en/docs/kitex/Tutorials/framework-exten/trans_pipeline.md index 53bbdbf0e3..5b6f467961 100644 --- a/content/en/docs/kitex/Tutorials/framework-exten/trans_pipeline.md +++ b/content/en/docs/kitex/Tutorials/framework-exten/trans_pipeline.md @@ -7,7 +7,7 @@ description: > ![remote_module](/img/docs/remote_module.png) -Transport Pipeline refers to Netty ChannelPipeline and provides `Inbound` and `Outbound` interfaces to support message or I/O event extensions. `TLS`, `Traffic Limit`, `Transparent Transmission Processing` can be extended based on `In/OutboundHandler`. As shown in the figure below, each BoundHandler is executed in series. +Transport Pipeline refers to Netty ChannelPipeline and provides `Inbound` and `Outbound` interfaces to support message or I/O event extensions. `TLS`, `Traffic Limit`, `Transparent Transmission Processing` can be extended based on `In/OutboundHandler`. As shown in the figure below, each BoundHandler is executed in series. ![trans_pipeline](/img/docs/trans_pipeline.png) @@ -45,19 +45,17 @@ type InboundHandler interface { Meta information transparent transmission is to transmit some RPC additional information to the downstream based on the transport protocol, and read the upstream transparent transmission information carried by transport protocol. The implementation is in transmeta_bound.go. - Write metainfo implements Write() - - Read metainfo implements OnMessage() - + - Read metainfo implements OnMessage() + In order to make it more convenient to extend Metadata Transparent Transmission for users, Kitex defines the separately extension API `MetaHandler`. - - ```go - // MetaHandler reads or writes metadata through certain protocol. - type MetaHandler interface { - WriteMeta(ctx context.Context, msg Message) (context.Context, error) - ReadMeta(ctx context.Context, msg Message) (context.Context, error) - } - ``` - - + + ```go + // MetaHandler reads or writes metadata through certain protocol. + type MetaHandler interface { + WriteMeta(ctx context.Context, msg Message) (context.Context, error) + ReadMeta(ctx context.Context, msg Message) (context.Context, error) + } + ``` ## Customized BoundHandler Usage @@ -76,6 +74,3 @@ type InboundHandler interface { ```go cli, err := xxxservice.NewClient(targetService, client.WithBoundHandler(yourBoundHandler)) ``` - - - diff --git a/content/en/docs/kitex/Tutorials/framework-exten/transmeta.md b/content/en/docs/kitex/Tutorials/framework-exten/transmeta.md index 7140372e6d..e5dbe7febe 100644 --- a/content/en/docs/kitex/Tutorials/framework-exten/transmeta.md +++ b/content/en/docs/kitex/Tutorials/framework-exten/transmeta.md @@ -77,5 +77,3 @@ func (ch *clientTTHeaderHandler) ReadMeta(ctx context.Context, msg remote.Messag ```go cli, err := xxxservice.NewClient(targetService, client.WithMetaHandler(transmeta.ClientTTHeaderHandler)) ``` - - \ No newline at end of file diff --git a/content/en/docs/kitex/Tutorials/framework-exten/transport.md b/content/en/docs/kitex/Tutorials/framework-exten/transport.md index 325e9cd6de..dd04a0e76d 100644 --- a/content/en/docs/kitex/Tutorials/framework-exten/transport.md +++ b/content/en/docs/kitex/Tutorials/framework-exten/transport.md @@ -53,13 +53,13 @@ Below figure is Kitex's extension to netpoll synchronous IO, which implements `E - Server Side - option: `WithTransServerFactory`, `WithTransHandlerFactory` + option: `WithTransServerFactory`, `WithTransHandlerFactory` ```go var opts []server.Option opts = append(opts, server.WithTransServerFactory(yourTransServerFactory) opts = append(opts, server.WithTransHandlerFactory(yourTransHandlerFactory) - + svr := xxxservice.NewServer(handler, opts...) ``` diff --git a/content/en/docs/kitex/Tutorials/observability/_index.md b/content/en/docs/kitex/Tutorials/observability/_index.md index de2cbf81e7..3ae44c1129 100644 --- a/content/en/docs/kitex/Tutorials/observability/_index.md +++ b/content/en/docs/kitex/Tutorials/observability/_index.md @@ -4,5 +4,4 @@ linkTitle: "Observability" weight: 3 date: 2023-04-19 description: > - --- diff --git a/content/en/docs/kitex/Tutorials/observability/instrumentation.md b/content/en/docs/kitex/Tutorials/observability/instrumentation.md index 6a0d4a2c02..f3ccca3201 100644 --- a/content/en/docs/kitex/Tutorials/observability/instrumentation.md +++ b/content/en/docs/kitex/Tutorials/observability/instrumentation.md @@ -7,17 +7,20 @@ description: Kitex supports flexible enabling of basic and fine-grained Instrume --- Stats Level: + 1. LevelDisabled, disable all events -2. LevelBase, enable basic events +2. LevelBase, enable basic events 3. LevelDetailed, enable basic events and detailed events. ## Stats Level Default Stats Level: + 1. No tracer is available, LevelDisabled by default 2. At least one tracer is available, LevelDetailed by default Client tracing stats level control: + ```go import "github.com/cloudwego/kitex/client" import "github.com/cloudwego/kitex/pkg/stats" @@ -30,6 +33,7 @@ if err != nil { ``` Server tracing stats level control: + ```go import "github.com/cloudwego/kitex/server" import "github.com/cloudwego/kitex/pkg/stats" diff --git a/content/en/docs/kitex/Tutorials/observability/monitoring.md b/content/en/docs/kitex/Tutorials/observability/monitoring.md index e8151c30bd..035de8cbfe 100644 --- a/content/en/docs/kitex/Tutorials/observability/monitoring.md +++ b/content/en/docs/kitex/Tutorials/observability/monitoring.md @@ -71,17 +71,17 @@ func main() { Client -| Name | Unit | Tags | Description | -|-----------------------------|------|--------------------------------------|-----------------------------------------| -| `kitex_client_throughput` | - | type, caller, callee, method, status | Total number of requests handled by the Client | -| `kitex_client_latency_us` | us | type, caller, callee, method, status | Latency of request handling at the Client (Response received time - Request initiation time, in microseconds) | +| Name | Unit | Tags | Description | +| ------------------------- | ---- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------- | +| `kitex_client_throughput` | - | type, caller, callee, method, status | Total number of requests handled by the Client | +| `kitex_client_latency_us` | us | type, caller, callee, method, status | Latency of request handling at the Client (Response received time - Request initiation time, in microseconds) | Server -| Name | Unit | Tags | Description | -|-----------------------------|------|--------------------------------------|-----------------------------------------| -| `kitex_server_throughput` | - | type, caller, callee, method, status | Total number of requests handled by the Server | -| `kitex_server_latency_us` | us | type, caller, callee, method, status | Latency of request handling at the Server (Processing completion time - Request received time, in microseconds) | +| Name | Unit | Tags | Description | +| ------------------------- | ---- | ------------------------------------ | --------------------------------------------------------------------------------------------------------------- | +| `kitex_server_throughput` | - | type, caller, callee, method, status | Total number of requests handled by the Server | +| `kitex_server_latency_us` | us | type, caller, callee, method, status | Latency of request handling at the Server (Processing completion time - Request received time, in microseconds) | More complex data monitoring can be implemented based on the above metrics. Examples can be found in the [Useful Examples](https://github.com/kitex-contrib/monitor-prometheus/?tab=readme-ov-file#useful-examples) section. @@ -101,15 +101,15 @@ For information on how to use obs-opentelemetry, please refer to the [tracing](. Server -| Name | Metric Data Model | Unit | Unit(UCUM) | Description | -|-----------------------------|-------------------|-------------|------------|-------------------------------------------| -| `rpc.server.duration` | Histogram | milliseconds| `ms` | measures duration of inbound RPC | +| Name | Metric Data Model | Unit | Unit(UCUM) | Description | +| --------------------- | ----------------- | ------------ | ---------- | -------------------------------- | +| `rpc.server.duration` | Histogram | milliseconds | `ms` | measures duration of inbound RPC | Client -| Name | Metric Data Model | Unit | Unit(UCUM) | Description | -|-----------------------------|-------------------|-------------|------------|-------------------------------------------| -| `rpc.server.duration` | Histogram | milliseconds| `ms` | measures duration of outbound RPC | +| Name | Metric Data Model | Unit | Unit(UCUM) | Description | +| --------------------- | ----------------- | ------------ | ---------- | --------------------------------- | +| `rpc.server.duration` | Histogram | milliseconds | `ms` | measures duration of outbound RPC | Additional service metrics can be calculated using `rpc.server.duration`, such as R.E.D (Rate, Errors, Duration). Examples can be found [here](https://github.com/kitex-contrib/obs-opentelemetry/blob/main/README.md#supported-metrics). @@ -118,12 +118,12 @@ Additional service metrics can be calculated using `rpc.server.duration`, such a Based on [opentelemetry-go](https://pkg.go.dev/go.opentelemetry.io/contrib/instrumentation/runtime), it supports the following runtime metrics: | Name | Instrument | Unit | Unit (UCUM)) | Description | -|----------------------------------------|------------|------------|--------------|-------------------------------------------------------------------------------| +| -------------------------------------- | ---------- | ---------- | ------------ | ----------------------------------------------------------------------------- | | `process.runtime.go.cgo.calls` | Sum | - | - | Number of cgo calls made by the current process. | | `process.runtime.go.gc.count` | Sum | - | - | Number of completed garbage collection cycles. | | `process.runtime.go.gc.pause_ns` | Histogram | nanosecond | `ns` | Amount of nanoseconds in GC stop-the-world pauses. | | `process.runtime.go.gc.pause_total_ns` | Histogram | nanosecond | `ns` | Cumulative nanoseconds in GC stop-the-world pauses since the program started. | -| `process.runtime.go.goroutines` | Gauge | - | - | measures duration of outbound RPC. | +| `process.runtime.go.goroutines` | Gauge | - | - | measures duration of outbound RPC. | | `process.runtime.go.lookups` | Sum | - | - | Number of pointer lookups performed by the runtime. | | `process.runtime.go.mem.heap_alloc` | Gauge | bytes | `bytes` | Bytes of allocated heap objects. | | `process.runtime.go.mem.heap_idle` | Gauge | bytes | `bytes` | Bytes in idle (unused) spans. | diff --git a/content/en/docs/kitex/Tutorials/options/_index.md b/content/en/docs/kitex/Tutorials/options/_index.md index 10983cd347..ece80bcb78 100644 --- a/content/en/docs/kitex/Tutorials/options/_index.md +++ b/content/en/docs/kitex/Tutorials/options/_index.md @@ -4,5 +4,4 @@ linkTitle: "Option" weight: 7 date: 2022-06-20 description: > - --- diff --git a/content/en/docs/kitex/Tutorials/options/call_options.md b/content/en/docs/kitex/Tutorials/options/call_options.md index 6b84f3d888..2d97034eb1 100644 --- a/content/en/docs/kitex/Tutorials/options/call_options.md +++ b/content/en/docs/kitex/Tutorials/options/call_options.md @@ -14,8 +14,6 @@ When a client makes an RPC call, it adds an additional Option that takes precede resp, err := client.Call(ctx, req, callopt.WithXXX....) ``` - - ## Options ### WithHostPort @@ -26,8 +24,6 @@ func WithHostPort(hostport string) Option Specifying a specific HostPort directly during this call phase will overwrite the resolver result for direct access. [More](/docs/kitex/tutorials/basic-feature/visit_directly/) - - ### WithURL ```go @@ -36,8 +32,6 @@ func WithURL(url string) Option Specifying a specified URL during this call phase to initiate the call. [More](/docs/kitex/tutorials/basic-feature/visit_directly/) - - ### WithTag ```go @@ -50,8 +44,6 @@ Set some meta information for this RPC call, add it in the form of key-value, fo resp, err := client.Call(ctx, req,callopt.WithTag("cluster", cluster),callopt.WithTag("idc", idc)) ``` - - ### WithRPCTimeout ```go @@ -60,8 +52,6 @@ func WithRPCTimeout(d time.Duration) Option Set RPC timeout. [More](/docs/kitex/tutorials/service-governance/timeout/) - - ### WithConnectTimeout ```go @@ -70,8 +60,6 @@ func WithConnectTimeout(d time.Duration) Option Set connection timeout. [More](/docs/kitex/tutorials/service-governance/timeout/) - - ### WithHTTPHost ```go diff --git a/content/en/docs/kitex/Tutorials/options/client_options.md b/content/en/docs/kitex/Tutorials/options/client_options.md index 79f6bf1b94..0affc6799e 100644 --- a/content/en/docs/kitex/Tutorials/options/client_options.md +++ b/content/en/docs/kitex/Tutorials/options/client_options.md @@ -14,8 +14,6 @@ Add some options when creating a client: client, err := echo.NewClient("targetService", client.WithXXXX...) ``` - - ## Basic Options ### WithClientBasicInfo @@ -27,8 +25,6 @@ func WithClientBasicInfo(ebi *rpcinfo.EndpointBasicInfo) Option Set the service infos for client, including ServiceName and customized Tags, customized Tag such as Cluster, IDC, Env, and it is no need to set Method field of EndpointBasicInfo. It is strongly recommended to configure this option. - - ### WithHostPorts ```go @@ -37,8 +33,6 @@ func WithHostPorts(hostports ...string) Option Manually specifie one or more targets overrides the results discovered by the service and directly connects to the access. - - ### WithTransportProtocol ```go @@ -57,8 +51,6 @@ func WithShortConnection() Option Enable short connections. [More](/docs/kitex/tutorials/basic-feature/connection_type/) - - ### WithLongConnection ```go @@ -67,8 +59,6 @@ func WithLongConnection(cfg connpool.IdleConfig) Option Enable long connections. [More](/docs/kitex/tutorials/basic-feature/connection_type/) - - ### WithMuxConnection ```go @@ -77,17 +67,13 @@ func WithMuxConnection(connNum int) Option Enable mux connections. Server side also need to turn on this option, or it won't work. [More](/docs/kitex/tutorials/basic-feature/connection_type/) - - ### WithMiddleware ```go func WithMiddleware(mw endpoint.Middleware) Option ``` -Add a middleware that executes after service level circuit breaker and timeout middleware. [More](/docs/kitex/tutorials/framework-exten/middleware/) - - +Add a middleware that executes after service level circuit breaker and timeout middleware. [More](/docs/kitex/tutorials/framework-exten/middleware/) ### WithInstanceMW @@ -97,8 +83,6 @@ func WithInstanceMW(mw endpoint.Middleware) Option Add a middleware that executes after service discovery and load balance. If instance level circuit breaker exists, then it will execute after that. (If proxy is used, it will not be called, such as mesh mode). [More](/docs/kitex/tutorials/framework-exten/middleware/) - - ### WithMiddlewareBuilder ```go @@ -107,8 +91,6 @@ func WithMiddlewareBuilder(mwb endpoint.MiddlewareBuilder) Option Add middleware depends on the context passed in by the framework that contains runtime configuration information (the context of non-RPC calls), so that the middleware can take advantage of the framework's information when initializing. - - ### WithCircuitBreaker ```go @@ -143,8 +125,6 @@ func WithFailureRetry(p *retry.FailurePolicy) Option Set timeout retry rules, you can configure the maximum number of retries, the maximum time spent accumulated, the threshold of the retry circuit fault rate, the DDL abort and backoff policy. [More](/docs/kitex/tutorials/service-governance/retry/) - - ### WithBackupRequest ```go @@ -153,8 +133,6 @@ func WithBackupRequest(p *retry.BackupPolicy) Option Set the policy for Backup Request, which can configure the number of requests, circuit breaker abort, and link abort. [More](/docs/kitex/tutorials/service-governance/retry/) - - ### WithRPCTimeout ```go @@ -163,8 +141,6 @@ func WithRPCTimeout(d time.Duration) Option Set RPC timeout. [More](/docs/kitex/tutorials/service-governance/timeout/) - - ### WithConnectTimeout ```go @@ -173,8 +149,6 @@ func WithConnectTimeout(d time.Duration) Option Set connect timeout. [More](/docs/kitex/tutorials/service-governance/timeout/) - - ### WithTimeoutProvider ```go @@ -183,8 +157,6 @@ func WithTimeoutProvider(p rpcinfo.TimeoutProvider) Option Add a TimeoutProvider to set the RPC timeout, connection timeout, etc. policies as a whole. If You use Both `WithRPCTimeout` or `WithConnectTimeout`, the settings here will be overridden. - - ### WithDestService ```go @@ -193,18 +165,14 @@ func WithDestService(svr string) Option Specify the service name of the target side of the call. - - ### WithTag ```go -func WithTag(key, val string) Option +func WithTag(key, val string) Option ``` Add some meta information to the client, such as idc, cluster, etc., for scenarios such as auxiliary service discovery. - - ### WithStatsLevel ```go @@ -213,8 +181,6 @@ func WithStatsLevel(level stats.Level) Optiong Set the stats level for client. [More](/docs/kitex/tutorials/observability/tracing/) - - ### gRPC Options > These options only works for scenarios where the transport protocol uses gRPC, with some parameter adjustments to gRPC transfers. @@ -227,8 +193,6 @@ func WithGRPCConnPoolSize(s uint32) Option WithGRPCConnPoolSize sets the value for the client connection pool size. In general, you should not adjust the size of the connection pool, otherwise it may cause performance degradation. You should adjust the size according to the actual situation. - - #### WithGRPCWriteBufferSize ```go @@ -238,8 +202,6 @@ func WithGRPCWriteBufferSize(s uint32) Option WithGRPCWriteBufferSize determines how much data can be batched before doing a write on the wire. The corresponding memory allocation for this buffer will be twice the size to keep syscalls low. The default value for this buffer is 32KB. Zero will disable the write buffer such that each write will be on underlying connection. Note: A Send call may not directly translate to a write. It corresponds to the WriteBufferSize ServerOption of gRPC. - - #### WithGRPCReadBufferSize ```go @@ -248,8 +210,6 @@ func WithGRPCReadBufferSize(s uint32) Option WithGRPCReadBufferSize lets you set the size of read buffer, this determines how much data can be read at most for one read syscall. The default value for this buffer is 32KB. Zero will disable read buffer for a connection so data framer can access the underlying conn directly. It corresponds to the ReadBufferSize ServerOption of gRPC. - - #### WithGRPCInitialWindowSize ```go @@ -258,8 +218,6 @@ func WithGRPCInitialWindowSize(s uint32) Option WithGRPCInitialWindowSize returns a Option that sets window size for stream. The lower bound for window size is 64K and any value smaller than that will be ignored. It corresponds to the InitialWindowSize ServerOption of gRPC. - - #### WithGRPCInitialConnWindowSize ```go @@ -268,8 +226,6 @@ func WithGRPCInitialConnWindowSize(s uint32) Option WithGRPCInitialConnWindowSize returns an Option that sets window size for a connection. The lower bound for window size is 64K and any value smaller than that will be ignored. It corresponds to the InitialConnWindowSize ServerOption of gRPC. - - #### WithGRPCMaxHeaderListSize ```go @@ -278,8 +234,6 @@ func WithGRPCMaxHeaderListSize(s uint32) Option WithGRPCMaxHeaderListSize returns a ServerOption that sets the max (uncompressed) size of header list that the server is prepared to accept. It corresponds to the MaxHeaderListSize ServerOption of gRPC. - - #### WithGRPCKeepaliveParams ```go @@ -288,17 +242,14 @@ func WithGRPCKeepaliveParams(kp grpc.ClientKeepalive) Option WithGRPCKeepaliveParams returns a DialOption that specifies keepalive parameters for the client transport. It corresponds to the WithKeepaliveParams DialOption of gRPC. - - #### WithGRPCTLSConfig + ```go func WithGRPCTLSConfig(tlsConfig *tls.Config) Option ``` WithGRPCTLSConfig sets the TLS config to the connection options for Kitex gRPC client. - - ## Advanced Options ### WithSuite @@ -309,8 +260,6 @@ func WithSuite(suite Suite) Option Set up a specific configuration, customize according to the scene, configure multiple options and middlewares combinations and encapsulations in the Suite. [More](/docs/kitex/tutorials/framework-exten/suite/) - - ### WithProxy ```go @@ -319,8 +268,6 @@ func WithProxy(p proxy.ForwardProxy) Option For proxy scenarios (such as Mesh Egress), do some configuration processing, return proxy address, configure proxy. After ForwardProxy, the framework does not perform service discovery, circuit breakers, and InstanceMWs. - - ### WithRetryContainer ```go @@ -344,7 +291,7 @@ If you have already configured the circuit breaker, it is recommended to reuse t - NewRetryContainer - Specifies the default RetryContainer for the retry policy, which has a built-in circuit breaker. -- NewRetryContainerWithCBStat +- NewRetryContainerWithCBStat To customize the built-in circuit breaker ServiceCBKeyFunc settings, you can use the NewRetryContainerWithCBStat method: @@ -353,12 +300,10 @@ To customize the built-in circuit breaker ServiceCBKeyFunc settings, you can use retry.NewRetryContainerWithCBStat(cbs.ServiceControl(), cbs.ServicePanel()) ``` - - ### WithWarmingUp ```go -func WithWarmingUp(wuo *warmup.ClientOption) Option +func WithWarmingUp(wuo *warmup.ClientOption) Option ``` Set warming up option. Kitex supports client warm-up, which allows you to pre-initialize the relevant components of service discovery and connection pooling when creating the client, avoiding large delays on the first request. @@ -391,8 +336,6 @@ cli, err := myservice.NewClient(psm, client.WithWarmingUp(&warmup.ClientOption{ })) ``` - - ### WithCloseCallbacks ```go @@ -401,8 +344,6 @@ func WithCloseCallbacks(callback func() error) Option Set close callback function. - - ### WithErrorHandler ```go @@ -411,8 +352,6 @@ func WithErrorHandler(f func(error) error) Option Set the error handler function, which is executed after the server handler is executed and before the middleware executes. - - ### WithGeneric ```go @@ -421,8 +360,6 @@ func WithGeneric(g generic.Generic) Option Specifie the generalization call type, which needs to be used in conjunction with the generalization Client/Server. [More](/docs/kitex/tutorials/advanced-feature/generic-call/) - - ### WithACLRules ```go @@ -431,8 +368,6 @@ func WithACLRules(rules ...acl.RejectFunc) Option Set ACL permission access control, which is executed before service discovery. [More](/docs/kitex/tutorials/service-governance/access_control/) - - ### WithConnReporterEnabled ```go @@ -441,18 +376,14 @@ func WithConnReporterEnabled() Option Enable connection pool reporter. [More](/docs/kitex/tutorials/basic-feature/connection_type/) - - ### WithHTTPConnection ```go -func WithHTTPConnection() Option +func WithHTTPConnection() Option ``` Specifie client use RPC over http. - - ## Extended Options ### WithTracer @@ -463,8 +394,6 @@ func WithTracer(c stats.Tracer) Option Add an additional Tracer. [More](/docs/kitex/tutorials/observability/tracing/) - - ### WithResolver ```go @@ -473,8 +402,6 @@ func WithResolver(r discovery.Resolver) Option Specifie a resolver to do service discovery. [More](/docs/kitex/tutorials/service-governance/service_discovery/) - - ### WithHTTPResolver ```go @@ -483,19 +410,15 @@ func WithHTTPResolver(r http.Resolver) Option Set HTTP resolver. [More](/docs/kitex/tutorials/basic-feature/visit_directly/) - - ### WithLoadBalancer ```go -func WithLoadBalancer(lb loadbalance.Loadbalancer, opts ...*lbcache.Options) Option +func WithLoadBalancer(lb loadbalance.Loadbalancer, opts ...*lbcache.Options) Option ``` Set load balancer. [More](/docs/kitex/tutorials/service-governance/loadbalance/) - - -### WithBoundHandler +### WithBoundHandler ```go func WithBoundHandler(h remote.BoundHandler) Option @@ -503,8 +426,6 @@ func WithBoundHandler(h remote.BoundHandler) Option Add a new IO Bound handler. [More](/docs/kitex/tutorials/framework-exten/trans_pipeline/) - - ### WithCodec ```go @@ -513,8 +434,6 @@ func WithCodec(c remote.Codec) Option Specifie a Codec for scenarios that require custom protocol. [More](/docs/kitex/tutorials/framework-exten/codec/) - - ### WithPayloadCodec ```go @@ -523,8 +442,6 @@ func WithPayloadCodec(c remote.PayloadCodec) Option Specifie a PayloadCodec. [More](/docs/kitex/tutorials/framework-exten/codec/) - - ### WithMetaHandler ```go @@ -533,8 +450,6 @@ func WithMetaHandler(h remote.MetaHandler) Option Add a meta handler for customizing transparent information in conjunction with the transport protocol, such as service name, invocation method, machine room, cluster, env, tracerInfo. [More](/docs/kitex/tutorials/framework-exten/transmeta/) - - ### WithFirstMetaHandler ```go @@ -543,18 +458,14 @@ func WithFirstMetaHandler(h remote.MetaHandler) Option Add a meta handler at the first position. - - ### WithTransHandlerFactory ```go -func WithTransHandlerFactory(f remote.ClientTransHandlerFactory) Option +func WithTransHandlerFactory(f remote.ClientTransHandlerFactory) Option ``` Set transHandlerFactory. [More](/docs/kitex/tutorials/framework-exten/transport/) - - ### WithDiagnosisService ```go @@ -563,8 +474,6 @@ func WithDiagnosisService(ds diagnosis.Service) Option Set diagnosis service. [More](/docs/kitex/tutorials/framework-exten/diagnosis/) - - ### WithDialer ```go @@ -573,8 +482,6 @@ func WithDialer(d remote.Dialer) Option Set dialer. - - ### WithConnPool ```go diff --git a/content/en/docs/kitex/Tutorials/options/server_options.md b/content/en/docs/kitex/Tutorials/options/server_options.md index f399867f97..84f1746174 100644 --- a/content/en/docs/kitex/Tutorials/options/server_options.md +++ b/content/en/docs/kitex/Tutorials/options/server_options.md @@ -14,8 +14,6 @@ Add some options when creating a server: svr := api.NewServer(new(DemoImpl), server.WithXXX...) ``` - - ## Basic Options ### WithServerBasicInfo @@ -27,8 +25,6 @@ func WithServerBasicInfo(ebi *rpcinfo.EndpointBasicInfo) Option Set the service infos for server, including ServiceName and customized Tags, customized Tag such as Cluster, IDC, Env, and it is no need to set Method field of EndpointBasicInfo. It is strongly recommended to configure this option, and those infos will be used for service registration. - - ### WithServiceAddr ```go @@ -44,17 +40,13 @@ Set the listen address for server. Default port is 8888, you can reset the port When local server has multiple IP addresses, you can also use this method to specify them. - - ### WithMuxTransport ```go func WithMuxTransport() Option ``` -Enable Kitex multiplexing transport feature on the server side. Client side also need to turn on this option, or it won't work. [More](/docs/kitex/tutorials/basic-feature/connection_type/) - - +Enable Kitex multiplexing transport feature on the server side. Client side also need to turn on this option, or it won't work. [More](/docs/kitex/tutorials/basic-feature/connection_type/) ### WithMiddleware @@ -62,9 +54,7 @@ Enable Kitex multiplexing transport feature on the server side. Client side also func WithMiddleware(mw endpoint.Middleware) Option ``` -Add a middleware. [More](/docs/kitex/tutorials/framework-exten/middleware/) - - +Add a middleware. [More](/docs/kitex/tutorials/framework-exten/middleware/) ### WithMiddlewareBuilder @@ -74,8 +64,6 @@ func WithMiddlewareBuilder(mwb endpoint.MiddlewareBuilder, funcName ...string) O Add middleware depends on the context passed in by the framework that contains runtime configuration information (the context of non-RPC calls), so that the middleware can take advantage of the framework's information when initializing. - - ### WithLimit ```go @@ -84,8 +72,6 @@ func WithLimit(lim *limit.Option) Option Set the throttling threshold, which allows you to set a limit on QPS and the number of connections, which uses a built-in throttling implementation that can be scaled if there is a custom throttling requirement, integrating your own throttling policy via `WithConcurrencyLimiter` or `WithQPSLimiter`. - - ### WithReadWriteTimeout ```go @@ -96,8 +82,6 @@ Set the server-side read and write timeout. Note: This feature may be changed or removed in subsequent releases. - - ### WithExitWaitTime ```go @@ -106,18 +90,14 @@ func WithExitWaitTime(timeout time.Duration) Option Set the wait time for graceful shutdown of graceful shutdown on the server side. - - ### WithMaxConnIdleTime ```go -func WithMaxConnIdleTime(timeout time.Duration) Option +func WithMaxConnIdleTime(timeout time.Duration) Option ``` Set the maximum amount of idle time allowed for the server-side connection to the client. - - ### WithStatsLevel ```go @@ -126,8 +106,6 @@ func WithStatsLevel(level stats.Level) Option Set the stats level for the server. [More](/docs/kitex/tutorials/observability/tracing/) - - ### gRPC Options > These options only works for scenarios where the transport protocol uses gRPC, with some parameter adjustments to gRPC transfers. @@ -141,10 +119,6 @@ func WithGRPCWriteBufferSize(s uint32) Option WithGRPCWriteBufferSize determines how much data can be batched before doing a write on the wire. The corresponding memory allocation for this buffer will be twice the size to keep syscalls low. The default value for this buffer is 32KB. Zero will disable the write buffer such that each write will be on underlying connection. Note: A Send call may not directly translate to a write. It corresponds to the WriteBufferSize ServerOption of gRPC. - - - - #### WithGRPCReadBufferSize ```go @@ -153,8 +127,6 @@ func WithGRPCReadBufferSize(s uint32) Option WithGRPCReadBufferSize lets you set the size of read buffer, this determines how much data can be read at most for one read syscall. The default value for this buffer is 32KB. Zero will disable read buffer for a connection so data framer can access the underlying conn directly. It corresponds to the ReadBufferSize ServerOption of gRPC. - - #### WithGRPCInitialWindowSize ```go @@ -163,8 +135,6 @@ func WithGRPCInitialWindowSize(s uint32) Option WithGRPCInitialWindowSize returns a Option that sets window size for stream. The lower bound for window size is 64K and any value smaller than that will be ignored. It corresponds to the InitialWindowSize ServerOption of gRPC. - - #### WithGRPCInitialConnWindowSize ```go @@ -173,8 +143,6 @@ func WithGRPCInitialConnWindowSize(s uint32) Option WithGRPCInitialConnWindowSize returns an Option that sets window size for a connection. The lower bound for window size is 64K and any value smaller than that will be ignored. It corresponds to the InitialConnWindowSize ServerOption of gRPC. - - #### WithGRPCKeepaliveParams ```go @@ -183,19 +151,13 @@ func WithGRPCKeepaliveParams(kp grpc.ServerKeepalive) Option WithGRPCKeepaliveParams returns an Option that sets keepalive and max-age parameters for the server. It corresponds to the KeepaliveParams ServerOption of gRPC. - - - - #### WithGRPCKeepaliveEnforcementPolicy ```go func WithGRPCKeepaliveEnforcementPolicy(kep grpc.EnforcementPolicy) Option ``` - WithGRPCKeepaliveEnforcementPolicy returns an Option that sets keepalive enforcement policy for the server. It corresponds to the KeepaliveEnforcementPolicy ServerOption of gRPC. - - +WithGRPCKeepaliveEnforcementPolicy returns an Option that sets keepalive enforcement policy for the server. It corresponds to the KeepaliveEnforcementPolicy ServerOption of gRPC. #### WithGRPCMaxConcurrentStreams @@ -205,8 +167,6 @@ func WithGRPCMaxConcurrentStreams(n uint32) Option WithGRPCMaxConcurrentStreams returns an Option that will apply a limit on the number of concurrent streams to each ServerTransport. It corresponds to the MaxConcurrentStreams ServerOption of gRPC. - - #### WithGRPCMaxHeaderListSize ```go @@ -215,10 +175,6 @@ func WithGRPCMaxHeaderListSize(s uint32) Option WithGRPCMaxHeaderListSize returns a ServerOption that sets the max (uncompressed) size of header list that the server is prepared to accept. It corresponds to the MaxHeaderListSize ServerOption of gRPC. - - - - ## Advanced Options ### WithSuite @@ -229,8 +185,6 @@ func WithSuite(suite Suite) Option Set up a specific configuration, customize according to the scene, configure multiple options and middlewares combinations and encapsulations in the Suite. [More](/docs/kitex/tutorials/framework-exten/suite/) - - ### WithProxy ```go @@ -239,8 +193,6 @@ func WithProxy(p proxy.ReverseProxy) Option If the server has a proxy, such as Mesh Ingress, you can modify the listening address through this configuration to communicate with the proxy, such as in the proxy. ReverseProxy modifies to the uds address. - - ### WithRegistryInfo ```go @@ -249,8 +201,6 @@ func WithRegistryInfo(info *registry.Info) Option Customize the registration information reported by the service. [More](/docs/kitex/tutorials/service-governance/service_discovery/) - - ### WithGeneric ```go @@ -259,8 +209,6 @@ func WithGeneric(g generic.Generic) Option Specify the generalization call type, which needs to be used in conjunction with the generalization Client/Server. [More](/docs/kitex/tutorials/advanced-feature/generic-call/) - - ### WithErrorHandler ```go @@ -269,8 +217,6 @@ func WithErrorHandler(f func(error) error) Option Set the error handler function, which is executed after the server handler is executed and before the middleware executes. - - ### WithACLRules ```go @@ -279,18 +225,14 @@ func WithACLRules(rules ...acl.RejectFunc) Option Set ACL permission access control, which is executed before service discovery. [More](/docs/kitex/tutorials/service-governance/access_control/) - - ### WithExitSignal ```go -func WithExitSignal(f func() <-chan error) Option +func WithExitSignal(f func() <-chan error) Option ``` Set the server exit signal. Kitex has a built-in implementation, if you need some customization can be implemented yourself. - - ### WithReusePort ```go @@ -299,8 +241,6 @@ func WithReusePort(reuse bool) Option Set port reuse, that is, whether to enable the underlying TCP port multiplexing mechanism. - - ## Extended Options ### WithRegistry @@ -311,8 +251,6 @@ func WithRegistry(r registry.Registry) Option Specify a Registry for service discovery registration reporting. [More](/docs/kitex/tutorials/service-governance/service_discovery/) - - ### WithTracer ```go @@ -321,8 +259,6 @@ func WithTracer(c stats.Tracer) Option Add an additional Tracer. [More](/docs/kitex/tutorials/observability/tracing/) - - ### WithCodec ```go @@ -331,8 +267,6 @@ func WithCodec(c remote.Codec) Option Specify a Codec for scenarios that require custom protocol. [More](/docs/kitex/tutorials/framework-exten/codec/) - - ### WithPayloadCodec ```go @@ -341,8 +275,6 @@ func WithPayloadCodec(c remote.PayloadCodec) Option Specifie a PayloadCodec. [More](/docs/kitex/tutorials/framework-exten/codec/) - - ### WithMetaHandler ```go @@ -351,8 +283,6 @@ func WithMetaHandler(h remote.MetaHandler) Option Add a meta handler for customizing transparent information in conjunction with the transport protocol, such as service name, invocation method, machine room, cluster, env, tracerInfo. [More](/docs/kitex/tutorials/framework-exten/transmeta/) - - ### WithBoundHandler ```go @@ -361,8 +291,6 @@ func WithBoundHandler(h remote.BoundHandler) Option Set IO Bound handlers. [More](/docs/kitex/tutorials/framework-exten/trans_pipeline/) - - ### WithConcurrencyLimiter ```go @@ -371,8 +299,6 @@ func WithConcurrencyLimiter(conLimit limiter.ConcurrencyLimiter) Option Set the concurrency limit for server. - - ### WithQPSLimiter ```go @@ -381,8 +307,6 @@ func WithQPSLimiter(qpsLimit limiter.RateLimiter) Option Set the QPS limit for server. - - ### WithLimitReporter ```go @@ -391,8 +315,6 @@ func WithLimitReporter(r limiter.LimitReporter) Option Set LimitReporter, and when QPS throttling or connection limiting occurs, you can customize the escalation through LimitReporter. - - ### WithTransHandlerFactory ```go @@ -401,8 +323,6 @@ func WithTransHandlerFactory(f remote.ServerTransHandlerFactory) Option Set transHandlerFactory. [More](/docs/kitex/tutorials/framework-exten/transport/) - - ### WithTransServerFactory ```go @@ -411,8 +331,6 @@ func WithTransServerFactory(f remote.TransServerFactory) Option Set transServerFactory. [More](/docs/kitex/tutorials/framework-exten/transport/) - - ### WithDiagnosisService ```go diff --git a/content/en/docs/kitex/Tutorials/service-governance/_index.md b/content/en/docs/kitex/Tutorials/service-governance/_index.md index ef90be2818..b0074d1af5 100644 --- a/content/en/docs/kitex/Tutorials/service-governance/_index.md +++ b/content/en/docs/kitex/Tutorials/service-governance/_index.md @@ -4,5 +4,4 @@ linkTitle: "Service Governance" weight: 2 date: 2021-08-31 description: > - ---- \ No newline at end of file +--- diff --git a/content/en/docs/kitex/Tutorials/service-governance/circuitbreaker.md b/content/en/docs/kitex/Tutorials/service-governance/circuitbreaker.md index 55699de3a0..ca7c2501ba 100644 --- a/content/en/docs/kitex/Tutorials/service-governance/circuitbreaker.md +++ b/content/en/docs/kitex/Tutorials/service-governance/circuitbreaker.md @@ -2,7 +2,7 @@ title: "Circuit Breaker" date: 2023-10-24 weight: 5 -keywords: ["Kitex - EN","Circuit Breaker"] +keywords: ["Kitex - EN", "Circuit Breaker"] description: "This doc covers Kitex Circuit Breaker use guide and principle introduction." --- @@ -31,17 +31,17 @@ func GenServiceCBKeyFunc(ri rpcinfo.RPCInfo) string { } func main() { - // build a new CBSuite with + // build a new CBSuite with cbs := circuitbreak.NewCBSuite(GenServiceCBKeyFunc) var opts []client.Option - + // add to the client options opts = append(opts, client.WithCircuitBreaker(cbs)) - - // init client + + // init client cli, err := echoservice.NewClient(targetService, opts...) - + // update circuit breaker config for a certain key (should be consistent with GenServiceCBKeyFunc) // this can be called at any time, and will take effect for following requests cbs.UpdateServiceCBConfig("fromServiceName/toServiceName/method", circuitbreak.CBConfig{ @@ -65,11 +65,13 @@ Kitex provides a set of CBSuite that encapsulates both service-level breaker and - Statistics by service granularity, enabled via WithMiddleware. - The specific service granularity depends on the Circuit Breaker Key, which is the key for breaker statistics. When initializing the CBSuite, you need to pass it in **GenServiceCBKeyFunc**. The default key is `circuitbreak.RPCInfo2Key`, and the format of RPCInfo2Key is `fromServiceName/toServiceName/method`. + - Instance-Level Breaker - Statistics by instance granularity, enabled via WithInstanceMW. - Instance-Level Breaker is used to solve the single-instance exception problem. If it’s triggered, the framework will automatically retry the request. - Note that the premise of retry is that you need to enable breaker with **WithInstanceMW**, which will be executed after load balancing. + - Threshold and **Threshold Change** The default breaker threshold is `ErrRate: 0.5, MinSample: 200`, which means it’s triggered by an error rate of 50% and requires the amount of requests > 200. @@ -86,7 +88,7 @@ To solve this problem, you can set up some dynamic switches that manually shut d A better approach, however, is to use Circuit Breaker. -Here is a more detailed document [Circuit Breaker Pattern](https://docs.microsoft.com/en-us/previous-versions/msp-n-p/dn589784(v=pandp.10)?redirectedfrom=MSDN). +Here is a more detailed document [Circuit Breaker Pattern](). One of the famous circuit breakers is hystrix, and here is its [design](https://github.com/Netflix/Hystrix/wiki). @@ -175,6 +177,7 @@ As an example: - (1) detects that bucket 0 has expired and discards it; - (2) creates a new bucket 10, corresponding to [10S, 11S); - (3) puts that Succ into bucket 10. + - At 10.2S, you execute Successes() to query the number of successes in the window, then you get the actual statistics for [1S, 10.2S), not [0.2S, 10.2S). Such jitter cannot be avoided if you use time-window-bucket statistics. A compromise approach is to increase the number of buckets, which can reduce the impact of jitter. diff --git a/content/en/docs/kitex/Tutorials/service-governance/config-center/_index.md b/content/en/docs/kitex/Tutorials/service-governance/config-center/_index.md index 6d7280e493..721aca6c04 100644 --- a/content/en/docs/kitex/Tutorials/service-governance/config-center/_index.md +++ b/content/en/docs/kitex/Tutorials/service-governance/config-center/_index.md @@ -5,7 +5,6 @@ date: 2023-11-29 weight: 2 keywords: ["ConfigCenter"] description: "ConfigCenter Extension provided by kitex-contrib" - --- ## Kitex provide configuration center @@ -19,7 +18,7 @@ Microservice developers can use the configuration center to dynamically obtain s Currently supported configuration centers are: | config-center | depository | -|:-------------:|:--------------------------------------------------------------------:| +| :-----------: | :------------------------------------------------------------------: | | nacos | [config-nacos](https://github.com/kitex-contrib/config-nacos) | | etcd | [config-etcd](https://github.com/kitex-contrib/config-etcd) | | apollo | [config-apollo](https://github.com/kitex-contrib/config-apollo) | @@ -32,12 +31,13 @@ Currently supported configuration centers are: In the process of connecting to the configuration center, Suite is used for third-party expansion. Suite is defined as follows: + ```go type Suite interface { Options() []Option } ``` + Both the server and the client use the WithSuite method to enable new suites. For more information about Suite, please see [Suite](../../framework-exten/suite) - diff --git a/content/en/docs/kitex/Tutorials/service-governance/config-center/apollo.md b/content/en/docs/kitex/Tutorials/service-governance/config-center/apollo.md index 727563c006..428d4e366b 100644 --- a/content/en/docs/kitex/Tutorials/service-governance/config-center/apollo.md +++ b/content/en/docs/kitex/Tutorials/service-governance/config-center/apollo.md @@ -2,15 +2,16 @@ title: "Apollo" date: 2023-12-12 weight: 2 -keywords: ["ConfigCenter Extension","apollo"] +keywords: ["ConfigCenter Extension", "apollo"] description: "Use apollo as Kitex’s service governance configuration center" - --- + ## Install `go get github.com/kitex-contrib/config-apollo` ## Suite + The configuration center adapter of apollo, kitex uses `WithSuite` to convert the configuration in apollo into the governance feature configuration of kitex. The following is a complete usage example: @@ -134,7 +135,7 @@ Create client. Function Signature: -``func NewClient(opts Options, optsfunc ...OptionFunc) (Client, error)`` +`func NewClient(opts Options, optsfunc ...OptionFunc) (Client, error)` Sample code: @@ -170,6 +171,7 @@ type ConfigParser interface { Sample code: Set the configuration for parsing json types. + ```go package main @@ -193,10 +195,10 @@ func main() { } ``` - ## Apollo Configuration ### Options Struct + ```go type Options struct { ConfigServerURL string @@ -208,7 +210,9 @@ type Options struct { ConfigParser ConfigParser } ``` + ### Options Variable + ```go type ConfigParamConfig struct { Category string @@ -216,18 +220,20 @@ type ConfigParamConfig struct { ServerServiceName string } ``` + The type of the namespace in kitex contrib/configure Apollo is properties, and the format reference for the key is as follows: ClientKeyFormat or ServerKeyFormat, with 'value' fixed in JSON format -| 参数 | 变量默认值 | 作用 | -| --------------- | --------------------------------------------- | ------------------------------------------------------------ | -| ConfigServerURL | 127.0.0.1:8080 | apollo config service address | -| AppID | KitexApp | appid of apollo (Uniqueness constraint / Length limit of 32 characters) | +| 参数 | 变量默认值 | 作用 | +| --------------- | --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ConfigServerURL | 127.0.0.1:8080 | apollo config service address | +| AppID | KitexApp | appid of apollo (Uniqueness constraint / Length limit of 32 characters) | | ClientKeyFormat | {{.ClientServiceName}}.{{.ServerServiceName}} | Using the go [template](https://pkg.go.dev/text/template) syntax to render and generate the corresponding ID, using two metadata: `ClientServiceName` and `ServiceName` (Length limit of 128 characters) | -| ServerKeyFormat | {{.ServerServiceName}} | Using the go [template](https://pkg.go.dev/text/template) Syntax rendering generates corresponding IDs, using 'ServiceName' as a single metadata (Length limit of 128 characters) | -| Cluster | default | Using default values, users can assign values as needed (Length limit of 32 characters) | -| ConfigParser | defaultConfigParser | The default parser, which defaults to parsing json format data (only parsing JSON format is supported currently) | +| ServerKeyFormat | {{.ServerServiceName}} | Using the go [template](https://pkg.go.dev/text/template) Syntax rendering generates corresponding IDs, using 'ServiceName' as a single metadata (Length limit of 128 characters) | +| Cluster | default | Using default values, users can assign values as needed (Length limit of 32 characters) | +| ConfigParser | defaultConfigParser | The default parser, which defaults to parsing json format data (only parsing JSON format is supported currently) | ### Governance Policy + > The namespace in the following example uses fixed policy values, with default values for AppID and Cluster. The service name is ServiceName and the client name is ClientName #### Rate Limit @@ -246,10 +252,9 @@ Category=limit Example: > namespace: `limit` -> +> > key: `ServiceName` - ```json { "connection_limit": 100, @@ -277,46 +282,46 @@ Category=retry Example: > namespace: `retry` -> +> > key: `ClientName.ServiceName` ```json { - "*": { - "enable": true, - "type": 0, - "failure_policy": { - "stop_policy": { - "max_retry_times": 3, - "max_duration_ms": 2000, - "cb_policy": { - "error_rate": 0.3 - } - }, - "backoff_policy": { - "backoff_type": "fixed", - "cfg_items": { - "fix_ms": 50 - } - }, - "retry_same_node": false + "*": { + "enable": true, + "type": 0, + "failure_policy": { + "stop_policy": { + "max_retry_times": 3, + "max_duration_ms": 2000, + "cb_policy": { + "error_rate": 0.3 } - }, - "echo": { - "enable": true, - "type": 1, - "backup_policy": { - "retry_delay_ms": 100, - "retry_same_node": false, - "stop_policy": { - "max_retry_times": 2, - "max_duration_ms": 300, - "cb_policy": { - "error_rate": 0.2 - } - } + }, + "backoff_policy": { + "backoff_type": "fixed", + "cfg_items": { + "fix_ms": 50 } + }, + "retry_same_node": false } + }, + "echo": { + "enable": true, + "type": 1, + "backup_policy": { + "retry_delay_ms": 100, + "retry_same_node": false, + "stop_policy": { + "max_retry_times": 2, + "max_duration_ms": 300, + "cb_policy": { + "error_rate": 0.2 + } + } + } + } } ``` @@ -331,7 +336,7 @@ Category=rpc_timeout Example: > namespace: `rpc_timeout` -> +> > key: `ClientName.ServiceName` ```json @@ -362,7 +367,7 @@ Category=circuit_break Example: > namespace: `circuit_break` -> +> > key: `ClientName.ServiceName` ```json @@ -370,8 +375,8 @@ The echo method uses the following configuration (0.3, 100) and other methods us { "echo": { "enable": true, - "err_rate": 0.3, - "min_sample": 100 + "err_rate": 0.3, + "min_sample": 100 } } ``` diff --git a/content/en/docs/kitex/Tutorials/service-governance/config-center/consul.md b/content/en/docs/kitex/Tutorials/service-governance/config-center/consul.md index 984b1909b5..93d7d08f56 100644 --- a/content/en/docs/kitex/Tutorials/service-governance/config-center/consul.md +++ b/content/en/docs/kitex/Tutorials/service-governance/config-center/consul.md @@ -258,19 +258,19 @@ type Options struct { ### Options defaults -| Parameter | Default | Description | -| ---------------- |--------------------------------------------------------- |---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Addr | 127.0.0.1:8500 | Consul server address | -| Prefix | /KitexConfig | The prefix of Consul | -| ServerPathFormat | {{.ServerServiceName}}/{{.Category}} | Use go [template](https://pkg.go.dev/text/template) syntax rendering to generate the appropriate ID, and use `ServiceName` `Category` two metadatas that can be customised, used with Prefix to form the key in etcd | +| Parameter | Default | Description | +| ---------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Addr | 127.0.0.1:8500 | Consul server address | +| Prefix | /KitexConfig | The prefix of Consul | +| ServerPathFormat | {{.ServerServiceName}}/{{.Category}} | Use go [template](https://pkg.go.dev/text/template) syntax rendering to generate the appropriate ID, and use `ServiceName` `Category` two metadatas that can be customised, used with Prefix to form the key in etcd | | ClientPathFormat | {{.ClientServiceName}}/{{.ServerServiceName}}/{{.Category}} | Use go [template](https://pkg.go.dev/text/template) syntax rendering to generate the appropriate ID, and use `ClientServiceName` `ServiceName` `Category` three metadata that can be customised, used with Prefix to form the key in consul | -| DataCenter | dc1 | Consul default data center | -| Timeout | 5 * time.Second | Timeout duration of 5s | -| NamespaceId | | Consul Namespace Id | -| Token | | Auth Token for Consul service | -| Partition | | Consul Partition | -| LoggerConfig | NULL | Default Logger | -| ConfigParser | defaultConfigParser | The default parser, which defaults to parsing json and yaml format data | +| DataCenter | dc1 | Consul default data center | +| Timeout | 5 \* time.Second | Timeout duration of 5s | +| NamespaceId | | Consul Namespace Id | +| Token | | Auth Token for Consul service | +| Partition | | Consul Partition | +| LoggerConfig | NULL | Default Logger | +| ConfigParser | defaultConfigParser | The default parser, which defaults to parsing json and yaml format data | ### Governance Policy diff --git a/content/en/docs/kitex/Tutorials/service-governance/config-center/etcd.md b/content/en/docs/kitex/Tutorials/service-governance/config-center/etcd.md index b70b999913..ce5af4bc5e 100644 --- a/content/en/docs/kitex/Tutorials/service-governance/config-center/etcd.md +++ b/content/en/docs/kitex/Tutorials/service-governance/config-center/etcd.md @@ -2,15 +2,16 @@ title: "Etcd" date: 2023-11-29 weight: 1 -keywords: ["ConfigCenter Extension","etcd"] +keywords: ["ConfigCenter Extension", "etcd"] description: "Use etcd as Kitex’s service governance configuration center" - --- + ## Install `go get github.com/kitex-contrib/config-etcd` ## Suite + The configuration center adapter of etcd, kitex uses `WithSuite` to convert the configuration in etcd into the governance feature configuration of kitex. The following is a complete usage example: @@ -167,6 +168,7 @@ type ConfigParser interface { Sample code: Set the configuration for parsing yaml types. + ```go package main @@ -187,10 +189,10 @@ func main() { } ``` - ## Etcd Configuration ### Options Struct + ```go type Options struct { Node []string @@ -202,38 +204,44 @@ type Options struct { ConfigParser ConfigParser } ``` + ### Options Variable + ```go type Key struct { Prefix string Path string } ``` + The key in etcd consists of prefix and path, where prefix is the prefix and path is the path. | Variable Name | Default Value | Introduction | -|------------------|-------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ---------------- | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Node | 127.0.0.1:2379 | Etcd server nodes | | Prefix | /KitexConfig | The prefix of Etcd | | ClientPathFormat | {{.ClientServiceName}}/{{.ServerServiceName}}/{{.Category}} | Use go [template](https://pkg.go.dev/text/template) syntax rendering to generate the appropriate ID, and use `ClientServiceName` `ServiceName` `Category` three metadata that can be customised, used with Prefix to form the key in etcd | | ServerPathFormat | {{.ServerServiceName}}/{{.Category}} | Use go [template](https://pkg.go.dev/text/template) syntax rendering to generate the appropriate ID, and use `ServiceName` `Category` two metadatas that can be customised, used with Prefix to form the key in etcd | -| Timeout | 5 * time.Second | five seconds timeout | +| Timeout | 5 \* time.Second | five seconds timeout | | LoggerConfig | NULL | Default Logger | | ConfigParser | defaultConfigParser | The default parser, which defaults to parsing json format data | ### Governance Policy + > The configPath and configPrefix in the following example use default values, the service name is `ServiceName` and the client name is `ClientName`. -#### Rate Limit +#### Rate Limit + Category=limit + > Currently, current limiting only supports the server side, so ClientServiceName is empty. [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/limiter/item_limiter.go#L33) | Variable | Introduction | -|------------------|------------------------------------| -| connection_limit | Maximum concurrent connections | -| qps_limit | Maximum request number every 100ms | +| ---------------- | ---------------------------------- | +| connection_limit | Maximum concurrent connections | +| qps_limit | Maximum request number every 100ms | Example: @@ -252,15 +260,16 @@ Note: - Not configured or value is 0 means not enabled. - connection_limit and qps_limit can be configured independently, e.g. connection_limit = 100, qps_limit = 0 -#### Retry Policy +#### Retry Policy + Category=retry [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/retry/policy.go#L63) | Variable | Introduction | -|-------------------------------|------------------------------------------------| -| type | 0: failure_policy 1: backup_policy | -| failure_policy.backoff_policy | Can only be set one of `fixed` `none` `random` | +| ----------------------------- | ---------------------------------------------- | +| type | 0: failure_policy 1: backup_policy | +| failure_policy.backoff_policy | Can only be set one of `fixed` `none` `random` | Example: @@ -268,46 +277,48 @@ Example: ```json { - "*": { - "enable": true, - "type": 0, - "failure_policy": { - "stop_policy": { - "max_retry_times": 3, - "max_duration_ms": 2000, - "cb_policy": { - "error_rate": 0.3 - } - }, - "backoff_policy": { - "backoff_type": "fixed", - "cfg_items": { - "fix_ms": 50 - } - }, - "retry_same_node": false + "*": { + "enable": true, + "type": 0, + "failure_policy": { + "stop_policy": { + "max_retry_times": 3, + "max_duration_ms": 2000, + "cb_policy": { + "error_rate": 0.3 + } + }, + "backoff_policy": { + "backoff_type": "fixed", + "cfg_items": { + "fix_ms": 50 } - }, - "echo": { - "enable": true, - "type": 1, - "backup_policy": { - "retry_delay_ms": 100, - "retry_same_node": false, - "stop_policy": { - "max_retry_times": 2, - "max_duration_ms": 300, - "cb_policy": { - "error_rate": 0.2 - } - } + }, + "retry_same_node": false + } + }, + "echo": { + "enable": true, + "type": 1, + "backup_policy": { + "retry_delay_ms": 100, + "retry_same_node": false, + "stop_policy": { + "max_retry_times": 2, + "max_duration_ms": 300, + "cb_policy": { + "error_rate": 0.2 } + } } + } } ``` + Note: retry.Container has built-in support for specifying the default configuration using the `*` wildcard (see the [getRetryer](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/retry/retryer.go#L240) method for details). -#### RPC Timeout +#### RPC Timeout + Category=rpc_timeout [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/rpctimeout/item_rpc_timeout.go#L42) @@ -328,16 +339,18 @@ Example: } } ``` + Note: The circuit breaker implementation of kitex does not currently support changing the global default configuration (see [initServiceCB](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/circuitbreak/cbsuite.go#L195) for details). #### Circuit Break + Category=circuit_break [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/circuitbreak/item_circuit_breaker.go#L30) | Variable | Introduction | -|------------|-----------------------------------| -| min_sample | Minimum statistical sample number | +| ---------- | --------------------------------- | +| min_sample | Minimum statistical sample number | Example: @@ -349,8 +362,8 @@ The echo method uses the following configuration (0.3, 100) and other methods us { "echo": { "enable": true, - "err_rate": 0.3, - "min_sample": 100 + "err_rate": 0.3, + "min_sample": 100 } } ``` diff --git a/content/en/docs/kitex/Tutorials/service-governance/config-center/file.md b/content/en/docs/kitex/Tutorials/service-governance/config-center/file.md index c769017aee..c5f2ef78e7 100644 --- a/content/en/docs/kitex/Tutorials/service-governance/config-center/file.md +++ b/content/en/docs/kitex/Tutorials/service-governance/config-center/file.md @@ -2,14 +2,14 @@ title: "File" date: 2023-12-18 weight: 4 -keywords: ["ConfigCenter Extension","file"] +keywords: ["ConfigCenter Extension", "file"] description: "Use local files as Kitex's service governance configuration center" - --- + ## Supported file type -| json | yaml | -| --- | --- | +| json | yaml | +| -------- | -------- | | ✔ | ✔ | ## Install @@ -17,6 +17,7 @@ description: "Use local files as Kitex's service governance configuration center `go get github.com/kitex-contrib/config-file` ## Suite + Local file configuration center adapter, kitex converts the configuration in local files into governance feature configurations of kitex through `WithSuite`. The usage can be divided into two steps: @@ -110,12 +111,14 @@ func main() { ``` ### Client + ```go type FileConfigClientSuite struct { watcher monitor.ConfigMonitor service string } ``` + Function Signature: `func NewSuite(service, key string, watcher filewatcher.FileWatcher,opts ...utils.Option)*FileConfigClientSuite` @@ -258,6 +261,7 @@ type ConfigParser interface { Sample: Extend parsing YAML types. + ```go // customed by user type MyParser struct{} @@ -299,26 +303,28 @@ client, err := echo.NewClient( In subsequent examples, we set the service name to `ServiceName` and the client name to `ClientName`. #### Rate Limit + Category=limit > Currently, current limiting only supports the server side, so ClientServiceName is empty. [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/limiter/item_limiter.go#L33) -|Variable|Introduction| -|----|----| -|connection_limit| Maximum concurrent connections | -|qps_limit| Maximum request number every 100ms | +| Variable | Introduction | +| ---------------- | ---------------------------------- | +| connection_limit | Maximum concurrent connections | +| qps_limit | Maximum request number every 100ms | Example: + ```json { - "ServiceName": { - "limit": { - "connection_limit": 300, - "qps_limit": 200 - } + "ServiceName": { + "limit": { + "connection_limit": 300, + "qps_limit": 200 } + } } ``` @@ -330,14 +336,15 @@ Note: - Multiple different rate limiting strategies for multiple services can be written within a single JSON file. Simply use filewatch to monitor the same file and pass in different keys. As shown in the example, the key is `ServiceName` #### Retry Policy + Category=retry [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/retry/policy.go#L63) -|Variable|Introduction| -|----|----| -|type| 0: failure_policy 1: backup_policy| -|failure_policy.backoff_policy| Can only be set one of `fixed` `none` `random` | +| Variable | Introduction | +| ----------------------------- | ---------------------------------------------- | +| type | 0: failure_policy 1: backup_policy | +| failure_policy.backoff_policy | Can only be set one of `fixed` `none` `random` | Example: @@ -345,42 +352,44 @@ Example: ```json { - "ClientName/ServiceName": { - "retry": { - "*": { - "enable": true, - "type": 0, - "failure_policy": { - "stop_policy": { - "max_retry_times": 3, - "max_duration_ms": 2000, - "cb_policy": { - "error_rate": 0.2 - } - } - } - }, - "Echo": { - "enable": true, - "type": 1, - "backup_policy": { - "retry_delay_ms": 200, - "stop_policy": { - "max_retry_times": 2, - "max_duration_ms": 1000, - "cb_policy": { - "error_rate": 0.3 - } - } - } + "ClientName/ServiceName": { + "retry": { + "*": { + "enable": true, + "type": 0, + "failure_policy": { + "stop_policy": { + "max_retry_times": 3, + "max_duration_ms": 2000, + "cb_policy": { + "error_rate": 0.2 } + } } + }, + "Echo": { + "enable": true, + "type": 1, + "backup_policy": { + "retry_delay_ms": 200, + "stop_policy": { + "max_retry_times": 2, + "max_duration_ms": 1000, + "cb_policy": { + "error_rate": 0.3 + } + } + } + } } + } } ``` + Note: retry.Container has built-in support for specifying the default configuration using the `*` wildcard (see the [getRetryer](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/retry/retryer.go#L240) method for details). #### RPC Timeout + Category=rpc_timeout [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/rpctimeout/item_rpc_timeout.go#L42) @@ -391,29 +400,30 @@ Example: ```json { - "ClientName/ServiceName": { - "timeout": { - "*": { - "conn_timeout_ms": 100, - "rpc_timeout_ms": 2000 - }, - "Pay": { - "conn_timeout_ms": 50, - "rpc_timeout_ms": 1000 - } - }, + "ClientName/ServiceName": { + "timeout": { + "*": { + "conn_timeout_ms": 100, + "rpc_timeout_ms": 2000 + }, + "Pay": { + "conn_timeout_ms": 50, + "rpc_timeout_ms": 1000 + } } + } } ``` #### Circuit Break + Category=circuit_break [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/circuitbreak/item_circuit_breaker.go#L30) -|Variable|Introduction| -|----|----| -|min_sample| Minimum statistical sample number| +| Variable | Introduction | +| ---------- | --------------------------------- | +| min_sample | Minimum statistical sample number | The echo method uses the following configuration (0.3, 100) and other methods use the global default configuration (0.5, 200) @@ -423,19 +433,20 @@ Example: ```json { - "ClientName/ServiceName": { - "circuitbreaker": { - "Echo": { - "enable": true, - "err_rate": 0.3, - "min_sample": 100 - } - }, + "ClientName/ServiceName": { + "circuitbreaker": { + "Echo": { + "enable": true, + "err_rate": 0.3, + "min_sample": 100 + } } + } } ``` Note: The circuit breaker implementation of kitex does not currently support changing the global default configuration (see [initServiceCB](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/circuitbreak/cbsuite.go#L195) for details). + #### More Info Refer to [example](https://github.com/kitex-contrib/config-file/tree/main/example) for more usage. @@ -448,54 +459,54 @@ For client configuration, you should write all their configurations in the same ```json { - "ClientName/ServiceName": { - "timeout": { - "*": { - "conn_timeout_ms": 100, - "rpc_timeout_ms": 2000 - }, - "Pay": { - "conn_timeout_ms": 50, - "rpc_timeout_ms": 1000 + "ClientName/ServiceName": { + "timeout": { + "*": { + "conn_timeout_ms": 100, + "rpc_timeout_ms": 2000 + }, + "Pay": { + "conn_timeout_ms": 50, + "rpc_timeout_ms": 1000 + } + }, + "circuitbreaker": { + "Echo": { + "enable": true, + "err_rate": 0.3, + "min_sample": 100 + } + }, + "retry": { + "*": { + "enable": true, + "type": 0, + "failure_policy": { + "stop_policy": { + "max_retry_times": 3, + "max_duration_ms": 2000, + "cb_policy": { + "error_rate": 0.2 } - }, - "circuitbreaker": { - "Echo": { - "enable": true, - "err_rate": 0.3, - "min_sample": 100 - } - }, - "retry": { - "*": { - "enable": true, - "type": 0, - "failure_policy": { - "stop_policy": { - "max_retry_times": 3, - "max_duration_ms": 2000, - "cb_policy": { - "error_rate": 0.2 - } - } - } - }, - "Echo": { - "enable": true, - "type": 1, - "backup_policy": { - "retry_delay_ms": 200, - "stop_policy": { - "max_retry_times": 2, - "max_duration_ms": 1000, - "cb_policy": { - "error_rate": 0.3 - } - } - } + } + } + }, + "Echo": { + "enable": true, + "type": 1, + "backup_policy": { + "retry_delay_ms": 200, + "stop_policy": { + "max_retry_times": 2, + "max_duration_ms": 1000, + "cb_policy": { + "error_rate": 0.3 } + } } + } } + } } ``` diff --git a/content/en/docs/kitex/Tutorials/service-governance/config-center/nacos.md b/content/en/docs/kitex/Tutorials/service-governance/config-center/nacos.md index ab83d758af..7e90662836 100644 --- a/content/en/docs/kitex/Tutorials/service-governance/config-center/nacos.md +++ b/content/en/docs/kitex/Tutorials/service-governance/config-center/nacos.md @@ -2,16 +2,17 @@ title: "Nacos" date: 2023-12-14 weight: 3 -keywords: ["ConfigCenter Extension","Nacos"] +keywords: ["ConfigCenter Extension", "Nacos"] description: "Use Nacos as Kitex’s service governance configuration center" --- ### Install + `go get github.com/kitex-contrib/config-nacos` ## Suite -The configuration center adapter of Nacos. +The configuration center adapter of Nacos. ### Server @@ -167,6 +168,7 @@ type ConfigParser interface { Sample: Extend parsing XML types. + ```go package main @@ -210,32 +212,35 @@ The configuration format supports `json` and `yaml`. You can use the [SetParser] ### CustomFunction -Provide the mechanism to custom the nacos parameter `vo.ConfigParam`. +Provide the mechanism to custom the nacos parameter `vo.ConfigParam`. ### Options Variable -| Variable Name | Default Value | Introduction | -| ------------------------- | ---------------------------------- | --------------------------------- | -| Address | 127.0.0.1 | Nacos server address, may use the environment of `serverAddr` | -| Port | 8848 | Nacos server port, may use the environment of `serverPort` | -| NamespaceID | | The namespaceID of Nacos, may use the environment of `namespace` | -| ClientDataIDFormat | {{.ClientServiceName}}.{{.ServerServiceName}}.{{.Category}} | Use go [template](https://pkg.go.dev/text/template) syntax rendering to generate the appropriate ID, and use `ClientServiceName` `ServiceName` `Category` three metadata that can be customised | -| ServerDataIDFormat | {{.ServerServiceName}}.{{.Category}} | Use go [template](https://pkg.go.dev/text/template) syntax rendering to generate the appropriate ID, and use `ServiceName` `Category` two metadatas that can be customised | -| Group | DEFAULT_GROUP | Use fixed values or dynamic rendering. Usage is the same as configDataId. | +| Variable Name | Default Value | Introduction | +| ------------------ | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Address | 127.0.0.1 | Nacos server address, may use the environment of `serverAddr` | +| Port | 8848 | Nacos server port, may use the environment of `serverPort` | +| NamespaceID | | The namespaceID of Nacos, may use the environment of `namespace` | +| ClientDataIDFormat | {{.ClientServiceName}}.{{.ServerServiceName}}.{{.Category}} | Use go [template](https://pkg.go.dev/text/template) syntax rendering to generate the appropriate ID, and use `ClientServiceName` `ServiceName` `Category` three metadata that can be customised | +| ServerDataIDFormat | {{.ServerServiceName}}.{{.Category}} | Use go [template](https://pkg.go.dev/text/template) syntax rendering to generate the appropriate ID, and use `ServiceName` `Category` two metadatas that can be customised | +| Group | DEFAULT_GROUP | Use fixed values or dynamic rendering. Usage is the same as configDataId. | ### Governance Policy + > The configDataId and configGroup in the following example use default values, the service name is `ServiceName` and the client name is `ClientName`. -#### Rate Limit +#### Rate Limit + Category=limit + > Currently, current limiting only supports the server side, so ClientServiceName is empty. [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/limiter/item_limiter.go#L33) -|Variable|Introduction| -|----|----| -|connection_limit| Maximum concurrent connections | -|qps_limit| Maximum request number every 100ms | +| Variable | Introduction | +| ---------------- | ---------------------------------- | +| connection_limit | Maximum concurrent connections | +| qps_limit | Maximum request number every 100ms | Example: @@ -254,14 +259,15 @@ Note: - Not configured or value is 0 means not enabled. - connection_limit and qps_limit can be configured independently, e.g. connection_limit = 100, qps_limit = 0 -#### Retry Policy +#### Retry Policy + Category=retry [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/retry/policy.go#L63) -|Variable|Introduction| -|----|----| -|type| 0: failure_policy 1: backup_policy| -|failure_policy.backoff_policy| Can only be set one of `fixed` `none` `random` | +| Variable | Introduction | +| ----------------------------- | ---------------------------------------------- | +| type | 0: failure_policy 1: backup_policy | +| failure_policy.backoff_policy | Can only be set one of `fixed` `none` `random` | Example: @@ -269,46 +275,48 @@ Example: ```json { - "*": { - "enable": true, - "type": 0, - "failure_policy": { - "stop_policy": { - "max_retry_times": 3, - "max_duration_ms": 2000, - "cb_policy": { - "error_rate": 0.3 - } - }, - "backoff_policy": { - "backoff_type": "fixed", - "cfg_items": { - "fix_ms": 50 - } - }, - "retry_same_node": false + "*": { + "enable": true, + "type": 0, + "failure_policy": { + "stop_policy": { + "max_retry_times": 3, + "max_duration_ms": 2000, + "cb_policy": { + "error_rate": 0.3 } - }, - "echo": { - "enable": true, - "type": 1, - "backup_policy": { - "retry_delay_ms": 100, - "retry_same_node": false, - "stop_policy": { - "max_retry_times": 2, - "max_duration_ms": 300, - "cb_policy": { - "error_rate": 0.2 - } - } + }, + "backoff_policy": { + "backoff_type": "fixed", + "cfg_items": { + "fix_ms": 50 + } + }, + "retry_same_node": false + } + }, + "echo": { + "enable": true, + "type": 1, + "backup_policy": { + "retry_delay_ms": 100, + "retry_same_node": false, + "stop_policy": { + "max_retry_times": 2, + "max_duration_ms": 300, + "cb_policy": { + "error_rate": 0.2 } + } } + } } ``` + Note: retry.Container has built-in support for specifying the default configuration using the `*` wildcard (see the [getRetryer](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/retry/retryer.go#L240) method for details). -#### RPC Timeout +#### RPC Timeout + Category=rpc_timeout [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/rpctimeout/item_rpc_timeout.go#L42) @@ -329,16 +337,18 @@ Example: } } ``` + Note: The circuit breaker implementation of kitex does not currently support changing the global default configuration (see [initServiceCB](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/circuitbreak/cbsuite.go#L195) for details). -#### Circuit Break +#### Circuit Break + Category=circuit_break [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/circuitbreak/item_circuit_breaker.go#L30) -|Variable|Introduction| -|----|----| -|min_sample| Minimum statistical sample number| +| Variable | Introduction | +| ---------- | --------------------------------- | +| min_sample | Minimum statistical sample number | Example: @@ -350,18 +360,16 @@ The echo method uses the following configuration (0.3, 100) and other methods us { "echo": { "enable": true, - "err_rate": 0.3, - "min_sample": 100 + "err_rate": 0.3, + "min_sample": 100 } } ``` ## Note -Do not delete the config in nacos, otherwise the nacos sdk may produce a large warning log. +Do not delete the config in nacos, otherwise the nacos sdk may produce a large warning log. ## Compatibility -This Package use Nacos1.x client. The Nacos2.0 and Nacos1.0 Server are fully compatible with it. [see](https://nacos.io/en-us/docs/v2/upgrading/2.0.0-compatibility.html) - - +This Package use Nacos1.x client. The Nacos2.0 and Nacos1.0 Server are fully compatible with it. [see](https://nacos.io/en-us/docs/v2/upgrading/2.0.0-compatibility.html) diff --git a/content/en/docs/kitex/Tutorials/service-governance/config-center/zookeeper.md b/content/en/docs/kitex/Tutorials/service-governance/config-center/zookeeper.md index 839820846a..f2d01a1933 100644 --- a/content/en/docs/kitex/Tutorials/service-governance/config-center/zookeeper.md +++ b/content/en/docs/kitex/Tutorials/service-governance/config-center/zookeeper.md @@ -2,15 +2,16 @@ title: "Zookeeper" date: 2023-12-18 weight: 5 -keywords: ["ConfigCenter Extension","ZooKeeper"] +keywords: ["ConfigCenter Extension", "ZooKeeper"] description: "Use ZooKeeper as Kitex’s service governance configuration center" - --- + ## Install `go get github.com/kitex-contrib/config-zookeeper` ## Suite + The configuration center adapter of zookeeper, kitex uses `WithSuite` to convert the configuration in zookeeper into the governance feature configuration of kitex. The following is a complete usage example: @@ -233,19 +234,19 @@ type ConfigParam struct { The final path in kitex-contrib/config-zookeeper is a combination of Prefix and Path in ConfigParam: `param.Prefix + "/" + param.Path` -| Variable Name | Default Value | Introduction | -| ---------------- | ----------------------------------------------------------- | ------------------------------------------------------------ | -| Servers | 127.0.0.1:2181 | Zookeeper server nodes | -| Prefix | /KitexConfig | The prefix of Zookeeper | +| Variable Name | Default Value | Introduction | +| ---------------- | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Servers | 127.0.0.1:2181 | Zookeeper server nodes | +| Prefix | /KitexConfig | The prefix of Zookeeper | | ClientPathFormat | {{.ClientServiceName}}/{{.ServerServiceName}}/{{.Category}} | Use go [template](https://pkg.go.dev/text/template) syntax rendering to generate the appropriate ID, and use `ClientServiceName` `ServiceName` `Category` three metadata that can be customised | -| ServerPathFormat | {{.ServerServiceName}}/{{.Category}} | Use go [template](https://pkg.go.dev/text/template) syntax rendering to generate the appropriate ID, and use `ServiceName` `Category` two metadatas that can be customised | -| ConfigParser | defaultConfigParser | The default is the parser that parses json | +| ServerPathFormat | {{.ServerServiceName}}/{{.Category}} | Use go [template](https://pkg.go.dev/text/template) syntax rendering to generate the appropriate ID, and use `ServiceName` `Category` two metadatas that can be customised | +| ConfigParser | defaultConfigParser | The default is the parser that parses json | ### Governance Policy > The configPath and configPrefix in the following example use default values, the service name is `ServiceName` and the client name is `ClientName`. -#### Rate Limit +#### Rate Limit Category=limit @@ -269,15 +270,13 @@ Example: } ``` - - Note: - The granularity of the current limit configuration is server global, regardless of client or method. - Not configured or value is 0 means not enabled. - connection_limit and qps_limit can be configured independently, e.g. connection_limit = 100, qps_limit = 0 -#### Retry Policy +#### Retry Policy Category=retry @@ -332,11 +331,9 @@ Example: } ``` - - Note: retry.Container has built-in support for specifying the default configuration using the `*` wildcard (see the [getRetryer](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/retry/retryer.go#L240) method for details). -#### RPC Timeout +#### RPC Timeout Category=rpc_timeout @@ -359,8 +356,6 @@ Example: } ``` - - Note: The circuit breaker implementation of kitex does not currently support changing the global default configuration (see [initServiceCB](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/circuitbreak/cbsuite.go#L195) for details). #### Circuit Break diff --git a/content/en/docs/kitex/Tutorials/service-governance/fallback.md b/content/en/docs/kitex/Tutorials/service-governance/fallback.md index e190934245..47f62dfabd 100644 --- a/content/en/docs/kitex/Tutorials/service-governance/fallback.md +++ b/content/en/docs/kitex/Tutorials/service-governance/fallback.md @@ -6,7 +6,7 @@ keywords: ["Kitex", "Fallback"] description: Kitex Fallback Introduction and Usage Guide. --- -> **Support Version: >= v0.5.0 (go.mod dependencies: [github/cloudwego/kitex](https://github.com/cloudwego/kitex))** +> **Support Version: >= v0.5.0 (go.mod dependencies: [github/cloudwego/kitex](https://github.com/cloudwego/kitex))** > > Protobuf Generated code version: >=v0.5.0(The version can be found in the header of the generated code file and in the version comments.) > @@ -14,8 +14,8 @@ description: Kitex Fallback Introduction and Usage Guide. ## 1.Kitex Fallback Functional Description - After an RPC request fails, businesses usually take some fallback measures to ensure a valid response (such as constructing a default response when encountering timeouts or circuit breakers). Kitex's Fallback supports handling all exceptional requests. Additionally, as business exceptions maybe return through Resp (BaseResp), Fallback also supports handling Resp. + ### 1.1 Result types that support Fallback 1. **RPC** **Error**: RPC request exceptions such as timeout, circuit breaker, rate limiting, and protocol errors at the RPC level. @@ -65,8 +65,7 @@ Kitex provides two ways to define Fallback Func: The latter is more intuitive and user-friendly, but it is not compatible with APIs that have multiple request parameters. Therefore, the framework defaults to using the former method. - -**Use XXXArgs/XXXResult as req/resp parameters** +**Use XXXArgs/XXXResult as req/resp parameters** Note: You must replace the original return value using result.SetSuccess(yourFallbackResult). @@ -88,7 +87,7 @@ client.WithFallback( ) ``` -**Use actual RPC Req/Resp as parameters** +**Use actual RPC Req/Resp as parameters** By using the **fallback.UnwrapHelper** provided by Kitex, you can define a Fallback Func with the signature of RealReqRespFunc, whose parameter types are consistent with Handler's req and resp. @@ -114,9 +113,9 @@ client.WithFallback( #### 2.3.2 Construct your Fallback Policy -The default constructor method for creating a Fallback Policy is NewFallbackPolicy, the framework will trigger fallback execution for both errors and responses to make it easier for businesses to use.Also,the framework provides encapsulation for users who want to execute fallbacks for errors or timeouts/circuit breakers. +The default constructor method for creating a Fallback Policy is NewFallbackPolicy, the framework will trigger fallback execution for both errors and responses to make it easier for businesses to use.Also,the framework provides encapsulation for users who want to execute fallbacks for errors or timeouts/circuit breakers. -1. **Execute fallback based on judgment of both errors and responses** +1. **Execute fallback based on judgment of both errors and responses** ```Go // Method 1: XXXArgs/XXXResult as params @@ -139,7 +138,7 @@ fallback.NewFallbackPolicy( ) ``` -2. **Execute fallback only on Errors (including business errors)** +2. **Execute fallback only on Errors (including business errors)** The Fallback will not be executed for non-Errors. @@ -164,7 +163,7 @@ fallback.ErrorFallback( ) ``` -3. **Execute fallback only on timeout and circuit-breaker errors** +3. **Execute fallback only on timeout and circuit-breaker errors** The Fallback will not be executed for non-timeout and circuit-breaker error. @@ -190,12 +189,11 @@ The framework defaults to reporting monitoring data based on the original RPC re **Note**: If the original result was not an RPC failure (business error), but if an error is returned in the Fallback, even if EnableReportAsFallback is set, the framework will not report the Fallback result. | **Original Result** | **Whether to use EnableReportAsFallback()** | **Reported Result** | -|----------------------------------------------------------|---------------------------------------------|----------------------------------------------------------------------| +| -------------------------------------------------------- | ------------------------------------------- | -------------------------------------------------------------------- | | RPC Fail | YES | fallback result | | RPC Fail | NO | is_error=1
(rpcinfo.GetRPCInfo(ctx).Stats().Error() is not nil) | | Business Error(Biz Err or BaseResp Non-successful state) | YES/NO | is_error=0
(rpcinfo.GetRPCInfo(ctx).Stats().Error() is nil) | - ### 2.4 Configuration example #### **Example 1**: Only execute fallback for timeout and circuit-breaker errors, and reporting monitoring data based on the fallback result. @@ -237,5 +235,4 @@ xxxCli.XXXMethod(ctx, req, callopt.WithFallback(yourFallbackPolicy)) ### 3.2 Usage of Kitex Protobuf / Kitex gRPC - Fallback is supported for Kitex Protobuf and Kitex gRPC unary requests, but requires generated code version >=v0.5.0 (The version can be found in the header of the generated code file and in the version comments.) -- Kitex gRPC streaming requests do not support fallback. - +- Kitex gRPC streaming requests do not support fallback. diff --git a/content/en/docs/kitex/Tutorials/service-governance/limiting.md b/content/en/docs/kitex/Tutorials/service-governance/limiting.md index 2d3495ecbf..36d6fa0baa 100644 --- a/content/en/docs/kitex/Tutorials/service-governance/limiting.md +++ b/content/en/docs/kitex/Tutorials/service-governance/limiting.md @@ -19,6 +19,7 @@ Kitex supports the user-defined QPS limiter and connections limiter, and provide ## Use default rate limiter ### code example + ```go import "github.com/cloudwego/kitex/pkg/limit" diff --git a/content/en/docs/kitex/Tutorials/service-governance/loadbalance.md b/content/en/docs/kitex/Tutorials/service-governance/loadbalance.md index 63eaf148f5..be9e217207 100644 --- a/content/en/docs/kitex/Tutorials/service-governance/loadbalance.md +++ b/content/en/docs/kitex/Tutorials/service-governance/loadbalance.md @@ -21,7 +21,7 @@ Kitex uses WeightedRoundRobin by default. WeightedRoundRobin uses a round-robin strategy based on weights, which is also Kitex's default strategy. -This LoadBalancer will make all instances have the min inflight requests to reduce the overload of instance. +This LoadBalancer will make all instances have the min inflight requests to reduce the overload of instance. If all instances have the same weights, it will use a pure round-robin implementation to avoid extra overhead of weighting calculations. @@ -145,9 +145,9 @@ Therefore, when there are 10,000 instances, each instance weight is 10, and the Both build and request information are cached, so the latency of a normal request (no build is required) has nothing to do with the number of nodes: ``` -BenchmarkNewConsistPicker/10ins-16 12557137 81.1 ns/op 0 B/op 0 allocs/op -BenchmarkNewConsistPicker/100ins-16 13704381 82.3 ns/op 0 B/op 0 allocs/op -BenchmarkNewConsistPicker/1000ins-16 14418103 81.3 ns/op 0 B/op 0 allocs/op +BenchmarkNewConsistPicker/10ins-16 12557137 81.1 ns/op 0 B/op 0 allocs/op +BenchmarkNewConsistPicker/100ins-16 13704381 82.3 ns/op 0 B/op 0 allocs/op +BenchmarkNewConsistPicker/1000ins-16 14418103 81.3 ns/op 0 B/op 0 allocs/op BenchmarkNewConsistPicker/10000ins-16 13942186 81.0 ns/op 0 B/op 0 allocs/op ``` diff --git a/content/en/docs/kitex/Tutorials/service-governance/retry.md b/content/en/docs/kitex/Tutorials/service-governance/retry.md index c0fe15cea1..0a2e085777 100644 --- a/content/en/docs/kitex/Tutorials/service-governance/retry.md +++ b/content/en/docs/kitex/Tutorials/service-governance/retry.md @@ -28,25 +28,25 @@ Only one of the `Exception Retry` and `Backup Request` policies can be configure The default is for timeout retry only, and it can be configured to support specific exception or Resp retry. -Configuration Item|Default value|Description|Limit -----|----|----|---- -`MaxRetryTimes`|2|The first request is not included. If it is configured as 0, it means to stop retrying.|Value: [0-5] -`MaxDurationMS`|0|Including the time-consuming of the first failed request and the retry request. If the limit is reached, the subsequent retry will be stopped. 0 means unlimited. Note: if configured, the configuration item must be greater than the request timeout. -`EERThreshold`|10%|If the method-level request error rate exceeds the threshold, retry stops.|Value: (0-30%] -`ChainStop`|-|`Chain Stop` is enabled by default. If the upstream request is a retry request, it will not be retried.|>= v0.0.5 as the default policy. -`DDLStop`|false|If the timeout period of overall request chain is reached, the retry request won't be sent with this policy. Notice, Kitex doesn't provide build-in implementation, use `retry.RegisterDDLStop(ddlStopFunc)` to register is needed. -`BackOff`|None|Retry waiting strategy, `NoneBackOff` by default. Optional: `FixedBackOff`, `RandomBackOff`. -`RetrySameNode`|false|By default, Kitex selects another node to retry. If you want to retry on the same node, set this parameter to true. +| Configuration Item | Default value | Description | Limit | +| ------------------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | +| `MaxRetryTimes` | 2 | The first request is not included. If it is configured as 0, it means to stop retrying. | Value: [0-5] | +| `MaxDurationMS` | 0 | Including the time-consuming of the first failed request and the retry request. If the limit is reached, the subsequent retry will be stopped. 0 means unlimited. Note: if configured, the configuration item must be greater than the request timeout. | +| `EERThreshold` | 10% | If the method-level request error rate exceeds the threshold, retry stops. | Value: (0-30%] | +| `ChainStop` | - | `Chain Stop` is enabled by default. If the upstream request is a retry request, it will not be retried. | >= v0.0.5 as the default policy. | +| `DDLStop` | false | If the timeout period of overall request chain is reached, the retry request won't be sent with this policy. Notice, Kitex doesn't provide build-in implementation, use `retry.RegisterDDLStop(ddlStopFunc)` to register is needed. | +| `BackOff` | None | Retry waiting strategy, `NoneBackOff` by default. Optional: `FixedBackOff`, `RandomBackOff`. | +| `RetrySameNode` | false | By default, Kitex selects another node to retry. If you want to retry on the same node, set this parameter to true. | - `Backup Request` -Configuration Item|Default value|Description|Limit -----|----|----|---- -`RetryDelayMS`|-|Duration of waiting for initiating a Backup Requset when the first request is not returned. This parameter must be set manually. It is suggested to set as TP99. -`MaxRetryTimes`|1|The first request is not included. If it is configured as 0, it means to stop retrying.|Value: [0-2] -`EERThreshold`|10%|If the method-level request error rate exceeds the threshold, retry stops.|Value: (0-30%] -`ChainStop`|false|`Chain Stop` is enabled by default. If the upstream request is a retry request, it will not be retried after timeout.|>= v0.0.5 as the default policy. -`RetrySameNode`|false|By default, Kitex selects another node to retry. If you want to retry on the same node, set this parameter to true. +| Configuration Item | Default value | Description | Limit | +| ------------------ | ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------- | +| `RetryDelayMS` | - | Duration of waiting for initiating a Backup Requset when the first request is not returned. This parameter must be set manually. It is suggested to set as TP99. | +| `MaxRetryTimes` | 1 | The first request is not included. If it is configured as 0, it means to stop retrying. | Value: [0-2] | +| `EERThreshold` | 10% | If the method-level request error rate exceeds the threshold, retry stops. | Value: (0-30%] | +| `ChainStop` | false | `Chain Stop` is enabled by default. If the upstream request is a retry request, it will not be retried after timeout. | >= v0.0.5 as the default policy. | +| `RetrySameNode` | false | By default, Kitex selects another node to retry. If you want to retry on the same node, set this parameter to true. | ## How to use @@ -124,13 +124,13 @@ type ShouldResultRetry struct { - Specific Exception/Resp Implementation e.g. - - Resp: + - Resp: - Resp of Thrift and KitexProtobuf protocol correspond to *XXXResult in the generated code, not the real business Resp. To get the real Resp, you need to assert `interface{ GetResult() interface{} }`. + Resp of Thrift and KitexProtobuf protocol correspond to \*XXXResult in the generated code, not the real business Resp. To get the real Resp, you need to assert `interface{ GetResult() interface{} }`. - - Error: + - Error: - The error returned by the peer, kitex will be uniformly encapsulated as `kerrors.ErrRemoteOrNetwork`. For Thrift and KitexProtobuf, the following examples can get the Error Msg returned by the peer. For gRPC, if the peer returns an error constructed by `status.Error`, and the local can use `status.FromError(err)` to get `*status.Status`. Pay attention to `Status` needs to be provided by Kitex, and the package path is `github.com/cloudwego/kitex/pkg/remote/trans/nphttp2/status`. + The error returned by the peer, kitex will be uniformly encapsulated as `kerrors.ErrRemoteOrNetwork`. For Thrift and KitexProtobuf, the following examples can get the Error Msg returned by the peer. For gRPC, if the peer returns an error constructed by `status.Error`, and the local can use `status.FromError(err)` to get `*status.Status`. Pay attention to `Status` needs to be provided by Kitex, and the package path is `github.com/cloudwego/kitex/pkg/remote/trans/nphttp2/status`. ```go // retry with specify Resp for one method @@ -162,7 +162,7 @@ opts = append(opts, client.WithSpecifiedResultRetry(yourResultRetry)) In particular, for Thrift's Exception, although the rpc call layer returns an error, the internal processing of the framework is actually regarded as a one-time cost RPC request (because there is an actual return). If you want to judge it, you need to pay attention to two points: 1. Judge by resp instead of error. -2. If the method retry is successful, namely, `GetSuccess() != nil`, you need to reset Exception to nil. Because the retry uses the XXXResult, and the Resp and Exception correspond to the two fields of XXXResult. Exception has been set for the first, and the second successfully set to Resp. However, the framework layer will not reset Exception, and the user needs to reset it by himself. +2. If the method retry is successful, namely, `GetSuccess() != nil`, you need to reset Exception to nil. Because the retry uses the XXXResult, and the Resp and Exception correspond to the two fields of XXXResult. Exception has been set for the first, and the second successfully set to Resp. However, the framework layer will not reset Exception, and the user needs to reset it by himself. e.g. @@ -180,8 +180,6 @@ respRetry := func(resp interface{}, ri rpcinfo.RPCInfo) bool { } ``` - - #### Backup Request Configuration - Retry Delay recommendations @@ -332,7 +330,7 @@ retryReqCount, exist := metainfo.GetPersistentValue(ctx,retry.TransitKey) For example, `retryReqCount = 2`, which means the second retry request (excluding the first request), then the business degradation strategy can be adopted(non-retry requests do not have this information). ->Question: `Chain Stop` is enabled by default, is it necessary for services to identify retry requests? +> Question: `Chain Stop` is enabled by default, is it necessary for services to identify retry requests? ->Answer:`Chain Stop` means that the retry request on the chain will not be retried. Assuming that there is a request chain `A->B->C`, `A` sends a retry request to `B`, while during `B->C`, if a timeout occurs or `Backup` is configured, `B` will not send a retry request to `C`. If the service can identify the retry request, it can directly decide whether to continue the request to `C`. -In short, `Chain Stop` avoids retry amplification caused by `B` sending a retry request to `C`. The service's own control can completely avoid requests from `B` to `C`. +> Answer:`Chain Stop` means that the retry request on the chain will not be retried. Assuming that there is a request chain `A->B->C`, `A` sends a retry request to `B`, while during `B->C`, if a timeout occurs or `Backup` is configured, `B` will not send a retry request to `C`. If the service can identify the retry request, it can directly decide whether to continue the request to `C`. +> In short, `Chain Stop` avoids retry amplification caused by `B` sending a retry request to `C`. The service's own control can completely avoid requests from `B` to `C`. diff --git a/content/en/docs/kitex/Tutorials/service-governance/service_discovery/consul.md b/content/en/docs/kitex/Tutorials/service-governance/service_discovery/consul.md index 490a0b1dca..c40a4e0004 100644 --- a/content/en/docs/kitex/Tutorials/service-governance/service_discovery/consul.md +++ b/content/en/docs/kitex/Tutorials/service-governance/service_discovery/consul.md @@ -40,12 +40,12 @@ import ( ) func main() { - + r, err := consul.NewConsulRegister("127.0.0.1:8500") if err != nil { log.Fatal(err) } - + server := hello.NewServer(new(HelloImpl), server.WithRegistry(r), server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ ServiceName: "greet.server", })) diff --git a/content/en/docs/kitex/Tutorials/service-governance/service_discovery/etcd.md b/content/en/docs/kitex/Tutorials/service-governance/service_discovery/etcd.md index ecf5521f36..dc50affc82 100644 --- a/content/en/docs/kitex/Tutorials/service-governance/service_discovery/etcd.md +++ b/content/en/docs/kitex/Tutorials/service-governance/service_discovery/etcd.md @@ -116,7 +116,7 @@ Function signature: func NewEtcdRegistryWithRetry(endpoints []string, retryConfig *retry.Config, opts ...Option) (registry.Registry, error) ``` -Use `NewRetryConfig(opts ...Option) *Config` to create `Retry` configuration, see `Option` for configuration details. +Use `NewRetryConfig(opts ...Option) *Config` to create `Retry` configuration, see `Option` for configuration details. Example: @@ -205,11 +205,11 @@ After the service is registered to ETCD, it will regularly check the status of t **Default Configuration** -| Configuration | Default Value | description | -| ----------------------------------------------------- | ---------------- | ------------------------------------------------------------ | -| `WithMaxAttemptTimes(maxAttemptTimes uint) Option` | 5 | Used to set the maximum number of attempts, if 0, it means infinite attempts | -| `WithObserveDelay(observeDelay time.Duration) Option` | 30 * time.Second | Used to set the delay time for checking service status under normal connection conditions | -| `WithRetryDelay(t time.Duration) Option` | 10 * time.Second | Used to set the retry delay time after disconnecting | +| Configuration | Default Value | description | +| ----------------------------------------------------- | ----------------- | ----------------------------------------------------------------------------------------- | +| `WithMaxAttemptTimes(maxAttemptTimes uint) Option` | 5 | Used to set the maximum number of attempts, if 0, it means infinite attempts | +| `WithObserveDelay(observeDelay time.Duration) Option` | 30 \* time.Second | Used to set the delay time for checking service status under normal connection conditions | +| `WithRetryDelay(t time.Duration) Option` | 10 \* time.Second | Used to set the retry delay time after disconnecting | ## Service Discovery @@ -274,7 +274,7 @@ import ( etcd "github.com/kitex-contrib/registry-etcd" ) -func main() { +func main() { // creates a etcd based resolver with given username and password r, err := etcd.NewEtcdResolverWithAuth([]string{"127.0.0.1:2379"}, "username", "password") if err != nil { @@ -435,4 +435,3 @@ The configuration of Etcd client and server can be customized, refer to the conf ## Complete Example For more, see [example](https://github.com/kitex-contrib/registry-etcd/tree/main/example) 。 - diff --git a/content/en/docs/kitex/Tutorials/service-governance/service_discovery/eureka.md b/content/en/docs/kitex/Tutorials/service-governance/service_discovery/eureka.md index bf68e125f5..06c112d584 100644 --- a/content/en/docs/kitex/Tutorials/service-governance/service_discovery/eureka.md +++ b/content/en/docs/kitex/Tutorials/service-governance/service_discovery/eureka.md @@ -41,7 +41,7 @@ func main() { ... r = euregistry.NewEurekaRegistry([]string{"http://127.0.0.1:8080/eureka"}, 15*time.Second) svr := echo.NewServer(new(EchoImpl), server.WithRegistry(r), - server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "test"}), + server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "test"}), ) if err := svr.Run(); err != nil { log.Println("server stopped with error:", err) @@ -79,7 +79,7 @@ import ( func main() { ... r = resolver.NewEurekaResolver([]string{"http://127.0.0.1:8080/eureka"}) - client, err := echo.NewClient("echo", + client, err := echo.NewClient("echo", client.WithResolver(r), ) if err != nil { diff --git a/content/en/docs/kitex/Tutorials/service-governance/service_discovery/nacos.md b/content/en/docs/kitex/Tutorials/service-governance/service_discovery/nacos.md index 06c605ee5d..5c79135196 100644 --- a/content/en/docs/kitex/Tutorials/service-governance/service_discovery/nacos.md +++ b/content/en/docs/kitex/Tutorials/service-governance/service_discovery/nacos.md @@ -58,15 +58,15 @@ import ( ) func main() { - // ... + // ... r, err := registry.NewDefaultNacosRegistry() if err != nil { panic(err) } svr := echo.NewServer( - new(EchoImpl), + new(EchoImpl), server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "echo"}), - server.WithRegistry(r), + server.WithRegistry(r), ) if err := svr.Run(); err != nil { log.Println("server stopped with error:", err) @@ -104,7 +104,7 @@ func main() { sc := []constant.ServerConfig{ *constant.NewServerConfig("127.0.0.1", 8848), } - + cc := constant.ClientConfig{ NamespaceId: "public", TimeoutMs: 5000, @@ -115,7 +115,7 @@ func main() { Username: "your-name", Password: "your-password", } - + cli, err := clients.NewNamingClient( vo.NacosClientParam{ ClientConfig: &cc, @@ -125,8 +125,8 @@ func main() { if err != nil { panic(err) } - - svr := echo.NewServer(new(EchoImpl), + + svr := echo.NewServer(new(EchoImpl), server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "echo"}), server.WithRegistry(registry.NewNacosRegistry(cli)), ) @@ -160,7 +160,7 @@ Nacos extension provides `WithGroup` to help users configure the cluster in naco Function signature: ```go -func WithGroup(group string) Option +func WithGroup(group string) Option ``` ## Service Discovery @@ -199,10 +199,10 @@ import ( ) func main() { - // ... + // ... r, err := resolver.NewDefaultNacosResolver() if err != nil { - panic(err) + panic(err) } client, err := echo.NewClient("echo", client.WithResolver(r)) if err != nil { @@ -235,7 +235,7 @@ import ( // ... ) func main() { - // ... + // ... sc := []constant.ServerConfig{ *constant.NewServerConfig("127.0.0.1", 8848), } @@ -249,7 +249,7 @@ func main() { Username: "your-name", Password: "your-password", } - + cli, err := clients.NewNamingClient( vo.NacosClientParam{ ClientConfig: &cc, @@ -257,7 +257,7 @@ func main() { }, ) if err != nil { - panic(err) + panic(err) } client, err := echo.NewClient("echo", client.WithResolver(resolver.NewNacosResolver(cli)) if err != nil { @@ -288,7 +288,7 @@ Nacos extension provides `WithGroup` to help users configure the cluster in naco Function signature: ```go -func WithGroup(group string) Option +func WithGroup(group string) Option ``` ## How To Use @@ -374,6 +374,7 @@ func main() { } } ``` + ## Caution - The nacos/v2 version of kitex does not currently support creating multiple port examples in the same group multiple times. diff --git a/content/en/docs/kitex/Tutorials/service-governance/service_discovery/polaris.md b/content/en/docs/kitex/Tutorials/service-governance/service_discovery/polaris.md index 9a1ec6ab4c..12ada2d535 100644 --- a/content/en/docs/kitex/Tutorials/service-governance/service_discovery/polaris.md +++ b/content/en/docs/kitex/Tutorials/service-governance/service_discovery/polaris.md @@ -31,7 +31,7 @@ Example: ```go import ( // ... - + "github.com/cloudwego/kitex-examples/hello/kitex_gen/api" "github.com/cloudwego/kitex-examples/hello/kitex_gen/api/hello" "github.com/cloudwego/kitex/pkg/registry" @@ -87,7 +87,7 @@ Example: ```go import ( // ... - + "github.com/cloudwego/kitex-examples/hello/kitex_gen/api" "github.com/cloudwego/kitex-examples/hello/kitex_gen/api/hello" "github.com/cloudwego/kitex/client" diff --git a/content/en/docs/kitex/Tutorials/service-governance/service_discovery/rule-based.md b/content/en/docs/kitex/Tutorials/service-governance/service_discovery/rule-based.md index 406b5e30ab..2f1ea6cac8 100644 --- a/content/en/docs/kitex/Tutorials/service-governance/service_discovery/rule-based.md +++ b/content/en/docs/kitex/Tutorials/service-governance/service_discovery/rule-based.md @@ -24,21 +24,22 @@ This resolver needs an implemented Resolver, which is able to resolve instances 2. Define filter rules. - ```go - // Define a filter function. - // For example, only get the instances with a tag of {"k":"v"}. - filterFunc := func(ctx context.Context, instance []discovery.Instance) []discovery.Instance { - var res []discovery.Instance - for _, ins := range instance { - if v, ok := ins.Tag("k"); ok && v == "v" { - res = append(res, ins) - } - } - return res - } - // Construct the filterRule - filterRule := &FilterRule{Name: "rule-name", Funcs: []FilterFunc{filterFunc}} - ``` + ```go + // Define a filter function. + // For example, only get the instances with a tag of {"k":"v"}. + filterFunc := func(ctx context.Context, instance []discovery.Instance) []discovery.Instance { + var res []discovery.Instance + for _, ins := range instance { + if v, ok := ins.Tag("k"); ok && v == "v" { + res = append(res, ins) + } + } + return res + } + // Construct the filterRule + filterRule := &FilterRule{Name: "rule-name", Funcs: []FilterFunc{filterFunc}} + ``` + Notice: the FilterFuncs will be executed sequentially. 3. Configure the resolver @@ -49,16 +50,16 @@ This resolver needs an implemented Resolver, which is able to resolve instances "github.com/cloudwego/kitex/client" "github.com/cloudwego/kitex/pkg/discovery" ) - + // implement your resolver var newResolver discovery.Resolver - + // construct a RuleBasedResolver with the `newResolver` and `filterRule` tagResolver := ruleBasedResolver.NewRuleBasedResolver(resolver, filterRule) - + // add this option when construct Kitex Client - opt := client.WithResolver(tagResolver) - ``` + opt := client.WithResolver(tagResolver) + ``` ## Demo diff --git a/content/en/docs/kitex/Tutorials/service-governance/timeout.md b/content/en/docs/kitex/Tutorials/service-governance/timeout.md index 7f645a8716..0c993e8773 100644 --- a/content/en/docs/kitex/Tutorials/service-governance/timeout.md +++ b/content/en/docs/kitex/Tutorials/service-governance/timeout.md @@ -4,7 +4,6 @@ date: 2021-08-31 weight: 3 keywords: ["Kitex", "timeout"] description: "There are several types of Timeout in Kitex: Client connection timeout, Client RPC timeout, Server read/write timeout, and Server exit timeout." - --- ## How to Use @@ -16,6 +15,7 @@ description: "There are several types of Timeout in Kitex: Client connection tim ##### Connection Timeout (default=50ms) Note: + 1. This is the maximum waiting time for establishing a new connection; 2. It can be set to any value (no upper limit); if not set, the default value is 50ms; 3. If you frequently encounter "dial timeout", try increasing the value and using the long connection pool (see client.WithLongConnection). @@ -23,6 +23,7 @@ Note: ##### RPC Timeout (default=0, no limit) Note: + 1. This is the maximum time limit for one RPC call; If timeout occurs, `kerrors.ErrRPCTimeout` is returned; 2. Any value can be specified (no upper limit); if not specified, the default value is 0, meaning no timeout limit; 3. No retry will be sent by default in case of timeout. @@ -32,6 +33,7 @@ Note: ##### By code - Client Option (per-client config) Specified when initializing client: + ```go import "github.com/cloudwego/kitex/client" @@ -39,18 +41,21 @@ cli, err := xxx.NewClient(targetService, client.WithConnectTimeout(100 * time.Millisecond), client.WithRPCTimeout(2 * time.Second)) ``` + Note: The two configuration items can be specified independently as needed. ##### By code - Call Option(per-request config; priority over client option) Specified when sending the request: + ```go import "github.com/cloudwego/kitex/client/callopt" -rsp, err := cli.YourMethod(ctx, req, +rsp, err := cli.YourMethod(ctx, req, callopt.WithConnectTimeout(100 * time.Millisecond)) callopt.WithRPCTimeout(2 * time.Second)) ``` + Note: The two configuration items can be specified independently as needed. ##### Dynamic Config - TimeoutProvider (priority lower than the options above) @@ -58,6 +63,7 @@ Note: The two configuration items can be specified independently as needed. Applicable to scenarios that require dynamic configuration. Before each request, the Client will call the `TimeoutProvider`` specified to obtain RPCTimeout and ConnectionTimeout. Specify a user-defined `rpcinfo.TimeoutProvider` when initializing the client: + ```go import ( "github.com/cloudwego/kitex/client" @@ -78,6 +84,7 @@ cli, err := xxx.NewClient(targetService, opt) ##### Configuration Center Extension Available extension(s): + - [config-nacos](https://github.com/kitex-contrib/config-nacos): Use Nacos as the configuration center, support timeout, retry, circuitbreak, and server side limiter. #### Error for Timeout @@ -85,6 +92,7 @@ Available extension(s): ##### Request Timeout (kerrors.ErrRPCTimeout) When a request times out, the `error` received by the Client will be: + ```go &kerrors.DetailedError { basic: kerrors.ErrRPCTimeout, @@ -107,6 +115,7 @@ By default, reasons of ErrRPCTimeout may be: In some scenarios, it's necessary to distinguish these reasons, such as issuing multiple requests at the same time expecting only one request to be successful, and cancelling other requests. However, other requests cancelled are not regarded as RPC or business error, and should be filtered to avoid unwanted alarms. Considering compatibility, this configuration is disabled by default and needs to be set by code: + ```go import "github.com/cloudwego/kitex/pkg/rpctimeout" @@ -129,6 +138,7 @@ For example, Kitex sets a 1s timeout: - If the timeout is between 950ms and 1s, it's currently conservatively determined to be the timer set by Kitex because it can not be accurately judged. The threshold (50ms) can be modified under Kitex >= 0.7.1 by: + ```go rpctimeout.SetBusinessTimeoutThreshold(10 * time.Millisecond) ``` @@ -140,6 +150,7 @@ rpctimeout.SetBusinessTimeoutThreshold(10 * time.Millisecond) ##### ReadWriteTimeout (default=5s) NOTE: + 1. This is the maximum waiting time that can be tolerated for reading and writing data on the connection, mainly to prevent abnormal connections from blocking the goroutine. 2. This is not the Handler execution timeout; 3. It only takes effect on the server side and it won't be a problem in most cases. @@ -149,6 +160,7 @@ For example, on the client side, request is sent in multiple segments. If the in ##### ExitWaitTime(default=5s) NOTE: + 1. After receiving an exit signal, the server will wait for an ExitWaitTime before exit; 2. If the waiting time is exceeded, the server will forcibly terminate all requests being processed (the client will receive an error). @@ -161,6 +173,7 @@ NOTE: For detailed usage, please refer to the example code below. NOTE: + - For Streaming API requests: enabled by default via another way - Including GRPC/Protobuf and Thrift Streaming - Client's `ctx.Deadline()` is sent via header `grpc-timeout` to server which will be added to the server request's ctx @@ -202,12 +215,14 @@ svr := yourservice.NewServer(handler, This Option should be used with TTHeader; please refer to the example code below. Client + - Specify TTHeader as Transport Protocol - Enable [transmeta.ClientTTHeaderHandler](https://github.com/cloudwego/kitex/blob/v0.9.0/pkg/transmeta/ttheader.go#L45) - Specify an RPC timeout by client.WithRPCTimeout (or by callopt.WithRPCTimeout when sending a request) + ```go cli := yourservice.MustNewClient( - serverName, + serverName, client.WithTransportProtocol(transport.TTHeader), client.WithMetaHandler(transmeta.ClientTTHeaderHandler), client.WithRPCTimeout(time.Second), @@ -215,8 +230,10 @@ cli := yourservice.MustNewClient( ``` Server + - Specify this option - Enable [transmeta.ServerTTHeaderHandler](https://github.com/cloudwego/kitex/blob/v0.9.0/pkg/transmeta/ttheader.go#L46) + ``` svr := yourservice.NewServer(handler, server.WithMetaHandler(transmeta.ServerTTHeaderHandler), @@ -224,7 +241,6 @@ svr := yourservice.NewServer(handler, ) ``` - ## FAQ ### Q: Will the server report a timeout if a handler executes more than ReadWriteTimeout(5s)? @@ -233,4 +249,4 @@ This is the timeout time waiting for the packet during server-side decoding, and ### Q: Does the server support handler timeout? -Currently, the server side does not support handler execution timeout. \ No newline at end of file +Currently, the server side does not support handler execution timeout. diff --git a/content/en/docs/kitex/_index.md b/content/en/docs/kitex/_index.md index 479349aee1..8c8f73c45b 100644 --- a/content/en/docs/kitex/_index.md +++ b/content/en/docs/kitex/_index.md @@ -1,10 +1,10 @@ --- -title: 'Kitex' -linkTitle: 'Kitex' +title: "Kitex" +linkTitle: "Kitex" weight: 1 Description: Kitex [kaɪt'eks] is a **high-performance** and **strong-extensibility** Golang RPC framework that helps developers build microservices. If the performance and extensibility are the main concerns when you develop microservices, Kitex can be a good choice. menu: main: weight: 1 - parent: 'Documentation' + parent: "Documentation" --- diff --git a/content/en/docs/netpoll/Common Usage/_index.md b/content/en/docs/netpoll/Common Usage/_index.md index 6bcca49ab0..6eebab1003 100644 --- a/content/en/docs/netpoll/Common Usage/_index.md +++ b/content/en/docs/netpoll/Common Usage/_index.md @@ -33,9 +33,9 @@ each poller. The following strategies are supported now: 1. Random - * The new connection will be assigned to a randomly picked poller. + - The new connection will be assigned to a randomly picked poller. 2. RoundRobin - * The new connection will be assigned to the poller in order. + - The new connection will be assigned to the poller in order. Netpoll uses `RoundRobin` by default, and users can change it in the following ways: @@ -138,10 +138,10 @@ func prepare(connection netpoll.Connection) (ctx context.Context) { Netpoll now supports two timeout configurations: 1. `Read Timeout` - * In order to maintain the same operating style as `net.Conn`, `Connection.Reader` is also designed to block - reading. So provide `Read Timeout`. - * `Read Timeout` has no default value(wait infinitely), it can be configured via `Connection` or `EventLoop.Option`, - for example: + - In order to maintain the same operating style as `net.Conn`, `Connection.Reader` is also designed to block + reading. So provide `Read Timeout`. + - `Read Timeout` has no default value(wait infinitely), it can be configured via `Connection` or `EventLoop.Option`, + for example: ```go package main @@ -165,13 +165,13 @@ func main() { ``` 2. `Idle Timeout` - * `Idle Timeout` utilizes the `TCP KeepAlive` mechanism to kick out dead connections and reduce maintenance - overhead. When using Netpoll, there is generally no need to create and close connections frequently, - and idle connections have little effect. When the connection is inactive for a long time, in order to prevent dead - connection caused by suspended animation, hang of the opposite end, abnormal disconnection, etc., the connection - will be actively closed after the `Idle Timeout`. - * The default minimum value of `Idle Timeout` is `10min`, which can be configured through `Connection` API - or `EventLoop.Option`, for example: + - `Idle Timeout` utilizes the `TCP KeepAlive` mechanism to kick out dead connections and reduce maintenance + overhead. When using Netpoll, there is generally no need to create and close connections frequently, + and idle connections have little effect. When the connection is inactive for a long time, in order to prevent dead + connection caused by suspended animation, hang of the opposite end, abnormal disconnection, etc., the connection + will be actively closed after the `Idle Timeout`. + - The default minimum value of `Idle Timeout` is `10min`, which can be configured through `Connection` API + or `EventLoop.Option`, for example: ```go package main diff --git a/content/en/docs/netpoll/Getting started/_index.md b/content/en/docs/netpoll/Getting started/_index.md index c37a06143a..92b69affc0 100644 --- a/content/en/docs/netpoll/Getting started/_index.md +++ b/content/en/docs/netpoll/Getting started/_index.md @@ -6,7 +6,7 @@ description: > --- > This tutorial gets you started with [Netpoll][Netpoll] through some simple [examples][Examples], includes how to -use [Server](#1-use-server), [Client](#2-use-dialer) and [nocopy APIs](#3-use-nocopy-api). +> use [Server](#1-use-server), [Client](#2-use-dialer) and [nocopy APIs](#3-use-nocopy-api). ## 1. Use Server @@ -54,8 +54,8 @@ etc. params: -* `OnRequest` and `OnConnect` are interface that users should implement by themselves to process business logic. [Code Comment][eventloop.go] describes their behavior in detail. -* `Option` is used to customize the configuration when creating `EventLoop`, and the following example shows its usage. +- `OnRequest` and `OnConnect` are interface that users should implement by themselves to process business logic. [Code Comment][eventloop.go] describes their behavior in detail. +- `Option` is used to customize the configuration when creating `EventLoop`, and the following example shows its usage. For more details, please refer to [options][netpoll_options.go]. The creation process is as follows: @@ -308,19 +308,11 @@ func main() { ``` [Netpoll]: https://github.com/cloudwego/netpoll - [net]: https://github.com/golang/go/tree/master/src/net - [gopool]: https://github.com/bytedance/gopkg/tree/develop/util/gopool - [Examples]: https://github.com/cloudwego/netpoll-examples - [server-example]: https://github.com/cloudwego/netpoll-examples/blob/main/echo/server.go - [client-example]: https://github.com/cloudwego/netpoll-examples/blob/main/echo/client.go - [netpoll_options.go]: https://github.com/cloudwego/netpoll/blob/main/netpoll_options.go - [nocopy.go]: https://github.com/cloudwego/netpoll/blob/main/nocopy.go - [eventloop.go]: https://github.com/cloudwego/netpoll/blob/main/eventloop.go diff --git a/content/en/docs/netpoll/Overview/_index.md b/content/en/docs/netpoll/Overview/_index.md index d9f0757b61..f45e8cfee2 100644 --- a/content/en/docs/netpoll/Overview/_index.md +++ b/content/en/docs/netpoll/Overview/_index.md @@ -3,7 +3,6 @@ title: "Overview" linkTitle: "Overview" weight: 1 description: > - --- ## Introduction @@ -32,24 +31,26 @@ We developed the RPC framework [Kitex][Kitex] and HTTP framework [Hertz][Hertz] ## Features -* **Already** - - [LinkBuffer][LinkBuffer] provides nocopy API for streaming reading and writing - - [gopool][gopool] provides high-performance goroutine pool - - [mcache][mcache] provides efficient memory reuse - - `IsActive` supports checking whether the connection is alive - - `Dialer` supports building clients - - `EventLoop` supports building a server - - TCP, Unix Domain Socket - - Linux, macOS (operating system) - -* **Future** - - [io_uring][io_uring] - - Shared Memory IPC - - TLS - - UDP - -* **Unsupported** - - Windows (operating system) +- **Already** + + - [LinkBuffer][LinkBuffer] provides nocopy API for streaming reading and writing + - [gopool][gopool] provides high-performance goroutine pool + - [mcache][mcache] provides efficient memory reuse + - `IsActive` supports checking whether the connection is alive + - `Dialer` supports building clients + - `EventLoop` supports building a server + - TCP, Unix Domain Socket + - Linux, macOS (operating system) + +- **Future** + + - [io_uring][io_uring] + - Shared Memory IPC + - TLS + - UDP + +- **Unsupported** + - Windows (operating system) ## Performance @@ -63,9 +64,8 @@ More benchmarks reference [kitex-benchmark][kitex-benchmark] and [hertz-benchmar ## Reference -* [Official Website](/) -* [Getting Started](/docs/netpoll/getting-started/) - +- [Official Website](/) +- [Getting Started](/docs/netpoll/getting-started/) [Netpoll]: https://github.com/cloudwego/netpoll [net]: https://github.com/golang/go/tree/master/src/net @@ -76,15 +76,12 @@ More benchmarks reference [kitex-benchmark][kitex-benchmark] and [hertz-benchmar [Kitex]: https://github.com/cloudwego/kitex [Hertz]: https://github.com/cloudwego/hertz [netpoll-example]: https://github.com/cloudwego/netpoll-examples - [netpoll-benchmark]: https://github.com/cloudwego/netpoll-benchmark [kitex-benchmark]: https://github.com/cloudwego/kitex-benchmark [hertz-benchmark]: https://github.com/cloudwego/hertz-benchmark - [ByteDance]: https://www.bytedance.com [Redis]: https://redis.io [HAProxy]: http://www.haproxy.org - [LinkBuffer]: https://github.com/cloudwego/netpoll/blob/develop/nocopy_linkbuffer.go [gopool]: https://github.com/bytedance/gopkg/tree/develop/util/gopool [mcache]: https://github.com/bytedance/gopkg/tree/develop/lang/mcache diff --git a/content/en/docs/netpoll/_index.md b/content/en/docs/netpoll/_index.md index 91f16a14c8..d31b9e38c2 100644 --- a/content/en/docs/netpoll/_index.md +++ b/content/en/docs/netpoll/_index.md @@ -1,10 +1,10 @@ --- -title: 'Netpoll' -linkTitle: 'Netpoll' +title: "Netpoll" +linkTitle: "Netpoll" weight: 4 Description: Netpoll is a high-performance non-blocking I/O networking framework, which focused on RPC scenarios, developed by ByteDance. menu: main: weight: 4 - parent: 'Documentation' + parent: "Documentation" --- diff --git a/content/en/docs/volo/_index.md b/content/en/docs/volo/_index.md index af26bc43e5..3dcbf0c420 100644 --- a/content/en/docs/volo/_index.md +++ b/content/en/docs/volo/_index.md @@ -1,10 +1,10 @@ --- -title: 'Volo' -linkTitle: 'Volo' +title: "Volo" +linkTitle: "Volo" weight: 3 Description: Volo is a **high-performance** and **strong-extensibility** Rust RPC framework that helps developers build microservices. menu: main: weight: 3 - parent: 'Documentation' + parent: "Documentation" --- diff --git a/content/en/docs/volo/faq/_index.md b/content/en/docs/volo/faq/_index.md index 1f36c9b060..9a39c63bce 100644 --- a/content/en/docs/volo/faq/_index.md +++ b/content/en/docs/volo/faq/_index.md @@ -11,8 +11,8 @@ description: Answers to frequently asked questions. If you've paid close attention, you'd notice that in the generated code on the client-side, we wrap the user-provided `Req` into `Arc` before actually executing the volo_thrift client's `call` method. However, on the server-side, we directly use `Req`. -The reason for this design is that the client-side requires more complex service governance logic compared to the server-side. -Especially, some service governance logic conflicts with Rust's ownership model. For instance, if a connection fails, we might need to retry on a different node or even implement more complex timeout-retry logic. +The reason for this design is that the client-side requires more complex service governance logic compared to the server-side. +Especially, some service governance logic conflicts with Rust's ownership model. For instance, if a connection fails, we might need to retry on a different node or even implement more complex timeout-retry logic. If we were to directly use `Req`, once we execute the inner service's `call` for the first time, the ownership would have already been moved, preventing us from implementing retry logic. Additionally, using `Arc` helps us avoid problems caused by concurrent access under middleware (such as scenarios involving mirror/diff), without going into excessive detail here. @@ -31,7 +31,7 @@ Volo is fully compatible with Kitex, including functionalities like metadata tra ### Where did poll_ready (backpressure) go? -In Tower's Service, there is a method called `poll_ready`, used to ensure downstream Services have sufficient processing capacity before making requests and to provide backpressure when processing capacity is insufficient. +In Tower's Service, there is a method called `poll_ready`, used to ensure downstream Services have sufficient processing capacity before making requests and to provide backpressure when processing capacity is insufficient. This is a very ingenious design, and Tower elaborates on the reasons for this design in the article [inventing-the-service-trait](https://tokio.rs/blog/2021-05-14-inventing-the-service-trait). However, based on our real development experience, we have summarized the following insights: diff --git a/content/en/docs/volo/guide/config.md b/content/en/docs/volo/guide/config.md index 0aad6427e2..bd454cc9ce 100644 --- a/content/en/docs/volo/guide/config.md +++ b/content/en/docs/volo/guide/config.md @@ -3,7 +3,6 @@ title: "volo.yml Configuration File Format" linkTitle: "volo.yml Configuration File Format" weight: 5 description: > - --- ## Features @@ -107,16 +106,16 @@ entries: 1. ```bash $ volo init --help init your thrift or grpc project - + Usage: volo init [OPTIONS] - + Arguments: The name of project Specify the path for idl. If -g or --git is specified, then this should be the path in the specified git repo. Example: -g not specified: ./idl/server.thrift -g specified: /path/to/idl/server.thrift - + Options: --repo Specify the git repo name for repo. Example: cloudwego_volo @@ -132,20 +131,20 @@ entries: -V, --version Print version ``` - 2. Using the `volo init` command in the project root directory will automatically create server code templates and generate code. + 2. Using the `volo init` command in the project root directory will automatically create server code templates and generate code. 2. idl 1. ```bash $ volo idl --help manage your idl - + Usage: volo idl [OPTIONS] - + Commands: add help Print this message or the help of the given subcommand(s) - + Options: -v, --verbose... Turn on the verbose mode. -n, --entry-name The entry name, defaults to 'default'. [default: default] @@ -158,13 +157,13 @@ entries: 1. ```bash $ volo idl add --help Usage: volo idl add [OPTIONS] - + Arguments: Specify the path for idl. If -g or --git is specified, then this should be the path in the specified git repo. Example: -g not specified: ./idl/client.thrift -g specified: /path/to/idl/client.thrift - + Options: --repo Specify the git repo name for repo. Example: cloudwego_volo @@ -189,14 +188,14 @@ entries: 1. ```bash $ volo repo --help manage your repo - + Usage: volo repo [OPTIONS] - + Commands: update update your repo by repo name, split by ',' add help Print this message or the help of the given subcommand(s) - + Options: -v, --verbose... Turn on the verbose mode. -n, --entry-name The entry name, defaults to 'default'. [default: default] @@ -209,7 +208,7 @@ entries: 1. ```bash $ volo repo add --help Usage: volo repo add [OPTIONS] --git - + Options: --repo Specify the git repo name for repo. Example: cloudwego_volo @@ -229,12 +228,12 @@ entries: 1. ```bash $ volo repo update --help update your repo by repo name, split by ',' - + Usage: volo repo update [OPTIONS] [REPOS]... - + Arguments: [REPOS]... - + Options: -v, --verbose... Turn on the verbose mode. -n, --entry-name The entry name, defaults to 'default'. [default: default] diff --git a/content/en/docs/volo/guide/discovery_lb.md b/content/en/docs/volo/guide/discovery_lb.md index 67909db343..496f1e66e5 100644 --- a/content/en/docs/volo/guide/discovery_lb.md +++ b/content/en/docs/volo/guide/discovery_lb.md @@ -3,10 +3,10 @@ title: "Custom Service Discovery and Load Balancing" linkTitle: "Custom Service Discovery and Load Balancing" weight: 2 description: > - --- ## Service Discovery + The `Discover` trait offers the capability for custom service discovery, supporting both static and subscribable service discovery functionalities. **Trait** Definition diff --git a/content/en/docs/volo/guide/metadata.md b/content/en/docs/volo/guide/metadata.md index 70d02b0d5a..17ebac55e1 100644 --- a/content/en/docs/volo/guide/metadata.md +++ b/content/en/docs/volo/guide/metadata.md @@ -3,7 +3,6 @@ title: "Metadata Propagation" linkTitle: "Metadata Propagation" weight: 4 description: > - --- ## Preface @@ -33,7 +32,6 @@ To use this feature with Volo-Thrift, TTHeader protocol is required; Volo-gRPC d If your scenario involves scaffolding code generated by Volo-Thrift server as the entry point, you can directly import the corresponding trait and perform retrieval or setting: - ```rust use metainfo::{Backward, Forward}; diff --git a/content/en/docs/volo/guide/observability.md b/content/en/docs/volo/guide/observability.md index 6f75bdce89..f72fed3055 100644 --- a/content/en/docs/volo/guide/observability.md +++ b/content/en/docs/volo/guide/observability.md @@ -3,7 +3,6 @@ title: "Custom Logging / Monitoring / Tracing" linkTitle: "Logging / Monitoring / Tracing" weight: 3 description: > - --- For RPC frameworks, logging, monitoring, and tracing are crucial components. Observability in cloud-native environments fundamentally relies on these three aspects. diff --git a/content/en/docs/volo/guide/with_callopt.md b/content/en/docs/volo/guide/with_callopt.md index 181b876be9..113cdd38b8 100644 --- a/content/en/docs/volo/guide/with_callopt.md +++ b/content/en/docs/volo/guide/with_callopt.md @@ -3,7 +3,6 @@ title: "Specifying CallOpt During Invocation" linkTitle: "Specifying CallOpt During Invocation" weight: 1 description: > - --- To enhance the framework's flexibility and user-friendliness, Volo allows users on the client-side to use `CallOpt` to set certain request metadata for individual requests. @@ -30,7 +29,6 @@ Within the `config`, various request configurations can be set, such as RPC time We can specify `CallOpt` during a request using the following method: - ```rust lazy_static! { static ref CLIENT: volo_gen::volo::example::ItemServiceClient = { diff --git a/content/en/docs/volo/motore/_index.md b/content/en/docs/volo/motore/_index.md index 2529cc1820..d1901947f5 100644 --- a/content/en/docs/volo/motore/_index.md +++ b/content/en/docs/volo/motore/_index.md @@ -1,8 +1,8 @@ --- -title: 'Motore' -linkTitle: 'Motore' +title: "Motore" +linkTitle: "Motore" weight: 6 -keywords: [ "Motore", "AFIT", "RPITIT"] +keywords: ["Motore", "AFIT", "RPITIT"] Description: Motore is an async middleware abstraction powered by AFIT and RPITIT. --- @@ -27,6 +27,7 @@ pub trait Service { async fn call<'s, 'cx>(&'s mut self, cx: &'cx mut Cx, req: Request) -> Result; } ``` + ## Getting Started Using AFIT, we can write asynchronous code in a very concise and readable way. diff --git a/content/en/docs/volo/overview/_index.md b/content/en/docs/volo/overview/_index.md index f60a03969a..59071c961e 100644 --- a/content/en/docs/volo/overview/_index.md +++ b/content/en/docs/volo/overview/_index.md @@ -4,7 +4,6 @@ linkTitle: "Overview" weight: 1 keywords: ["RPC", "Rust", "Volo", "AFIT", "RPITIT"] description: "The architecture design, framework features, and related ecology of Volo." - --- ## Volo diff --git a/content/en/docs/volo/pilota/_index.md b/content/en/docs/volo/pilota/_index.md index 3b386d8814..bff0f4bfcf 100644 --- a/content/en/docs/volo/pilota/_index.md +++ b/content/en/docs/volo/pilota/_index.md @@ -1,8 +1,8 @@ --- -title: 'Pilota' -linkTitle: 'Pilota' +title: "Pilota" +linkTitle: "Pilota" weight: 7 -keywords: [ "Pilota", "Thrift", "Protobuf", "Plugin"] +keywords: ["Pilota", "Thrift", "Protobuf", "Plugin"] Description: Pilota is a Thrift and Protobuf implementation in pure rust with high performance and extensibility. --- diff --git a/content/en/docs/volo/volo-grpc/_index.md b/content/en/docs/volo/volo-grpc/_index.md index cfbffe74a8..f5bf52b5ee 100644 --- a/content/en/docs/volo/volo-grpc/_index.md +++ b/content/en/docs/volo/volo-grpc/_index.md @@ -4,6 +4,4 @@ linkTitle: "Volo-gRPC" weight: 3 keywords: ["Volo", "gRPC", "Getting Started", "Guidelines"] description: "CLI tool installation, quick start and basic tutorials for Volo-gRPC." - --- - diff --git a/content/en/docs/volo/volo-thrift/_index.md b/content/en/docs/volo/volo-thrift/_index.md index 42f1a0568b..cfe560baf2 100644 --- a/content/en/docs/volo/volo-thrift/_index.md +++ b/content/en/docs/volo/volo-thrift/_index.md @@ -4,5 +4,4 @@ linkTitle: "Volo-Thrift" weight: 2 keywords: ["Volo", "Thrift", "Getting Started", "Guidelines"] description: "CLI tool installation, quick start and basic tutorials for Volo-Thrift." - --- diff --git a/content/en/search.md b/content/en/search.md index e3690fd5a8..394feea5fd 100644 --- a/content/en/search.md +++ b/content/en/search.md @@ -1,6 +1,4 @@ --- title: Search Results layout: search - --- - diff --git a/content/en/security/_index.md b/content/en/security/_index.md index 239cc110c5..0c704aec1f 100644 --- a/content/en/security/_index.md +++ b/content/en/security/_index.md @@ -1,14 +1,12 @@ --- -title: 'Security' -linkTitle: 'Security' +title: "Security" +linkTitle: "Security" isFolder: true menu: main: weight: 50 --- - This is the **security** section. It has two categories: vulnerability-reporting and safety-bulletin. Files in these directories will be listed in reverse chronological order. - diff --git a/content/en/security/safety-bulletin/detail/_index.md b/content/en/security/safety-bulletin/detail/_index.md index c31401622b..939a927e2e 100644 --- a/content/en/security/safety-bulletin/detail/_index.md +++ b/content/en/security/safety-bulletin/detail/_index.md @@ -3,4 +3,3 @@ title: "detail" linkTitle: "detail" weight: 1 --- - diff --git a/content/en/security/safety-bulletin/detail/cloudwego-sa-2022-1/index.md b/content/en/security/safety-bulletin/detail/cloudwego-sa-2022-1/index.md index 974fd2430d..531f53cce5 100644 --- a/content/en/security/safety-bulletin/detail/cloudwego-sa-2022-1/index.md +++ b/content/en/security/safety-bulletin/detail/cloudwego-sa-2022-1/index.md @@ -6,22 +6,29 @@ description: "Connection Leaking" --- ## Overview + Fixed connection leak when client encoding failed ## Severity Level + Low ## Description + Fixed connection leak when client encoding failed ## Solution + When client encoding fails, the connection is released ## Affected Components + kitex-v0.1.3 ## CVE + None ## References + - https://github.com/cloudwego/kitex/pull/315 diff --git a/content/en/security/safety-bulletin/detail/cloudwego-sa-2022-2/index.md b/content/en/security/safety-bulletin/detail/cloudwego-sa-2022-2/index.md index 4e7ce18e96..d9a55793ee 100644 --- a/content/en/security/safety-bulletin/detail/cloudwego-sa-2022-2/index.md +++ b/content/en/security/safety-bulletin/detail/cloudwego-sa-2022-2/index.md @@ -6,9 +6,11 @@ description: Netpoll Panic --- ## Overview + Fixed Panic when "peer Close & local user Close" occurs simultaneously ## Severity Level + Middle ## Description @@ -23,16 +25,20 @@ When the program is idle, it is possible that `c.onclose` has completed the `clo That's when the `op.unused` in `p.detaches` is executed; This will incorrectly set the operator of a new connection to 0, causing all subsequent `op.do` to fail in an infinite loop. ## Solution + `Poller` no longer executes `detach` asynchronously to ensure that it does not run concurrently with `C.onclose` and the changes are performance-neutral. ## Affected Components + netpoll-v0.2.2 kitex-v0.3.0 ## CVE + None ## References + - https://github.com/cloudwego/netpoll/issues/149 - https://github.com/cloudwego/netpoll/pull/142 diff --git a/content/zh/blog/_index.md b/content/zh/blog/_index.md index 265e89e1f6..d4b063da78 100644 --- a/content/zh/blog/_index.md +++ b/content/zh/blog/_index.md @@ -7,8 +7,6 @@ menu: weight: 20 --- - This is the **blog** section. It has two categories: News and Releases. Files in these directories will be listed in reverse chronological order. - diff --git a/content/zh/blog/news/1st_RPCKitex/index.md b/content/zh/blog/news/1st_RPCKitex/index.md index 1b87c4fa0b..ae1f314917 100644 --- a/content/zh/blog/news/1st_RPCKitex/index.md +++ b/content/zh/blog/news/1st_RPCKitex/index.md @@ -3,7 +3,19 @@ date: 2022-09-20 title: "高性能 RPC 框架 CloudWeGo-Kitex 内外统一的开源实践" projects: ["Kitex"] linkTitle: "高性能 RPC 框架 CloudWeGo-Kitex 内外统一的开源实践" -keywords: ["Kitex", "CloudWeGo", "RPC", "开源", "Kite", "Golang", "Thrift", "Protobuf", "gRPC", "xDS"] +keywords: + [ + "Kitex", + "CloudWeGo", + "RPC", + "开源", + "Kite", + "Golang", + "Thrift", + "Protobuf", + "gRPC", + "xDS", + ] description: "本文介绍了高性能 RPC 框架 CloudWeGo-Kitex 的起源与发展历史,以及开源一年以来的功能特性变更、社区共建生态成果、企业落地实践等方面。" author: YangruiEmma --- @@ -46,7 +58,7 @@ author: YangruiEmma 大家或许还有疑问,完整的微服务体系离不开基础的云生态,无论在公有云、私有云,都需要搭建额外的服务以很好地支持微服务的治理,比如治理平台、注册中心、配置中心、监控、链路跟踪、服务网格等,而且还存在一些定制的规范。 字节跳动自然也有完善的内部服务支持微服务体系,但这些服务短期还无法开源,那 CloudWeGo 如何内外维护一套代码,统一迭代呢? -关于这个问题,我们看一下 [Kitex][Kitex] 的模块划分。[Kitex][Kitex] 的模块分为三个部分:中间是 [Kitex][Kitex] 主干部分 **Kitex Core** ,它定义了框架的层次结构、接口核心逻辑的实现以及接口的默认实现; +关于这个问题,我们看一下 [Kitex][Kitex] 的模块划分。[Kitex][Kitex] 的模块分为三个部分:中间是 [Kitex][Kitex] 主干部分 **Kitex Core** ,它定义了框架的层次结构、接口核心逻辑的实现以及接口的默认实现; 左边的 **Kitex Tool** 则是与生成代码相关的实现,我们的生成代码工具就是编译这个包得到的,其中包括 IDL 的解析、校验、代码生成、插件支持等。 不过为了便于用户使用同时提供更友好的扩展,主要能力也做了拆分作为基础库独立开源,如 Thriftgo、Thrift-validator 插件、Fastpb; 右边的 **Kitex Byted** 是对字节内部基础能力集成的扩展实现,我们在开始就将内部的能力作为扩展收敛到一个 package 下。 @@ -81,20 +93,20 @@ bytedance/gopkg: https://github.com/bytedance/gopkg 在介绍 [Kitex][Kitex] 开源一年变更前,先分享一下框架的衡量指标,这是大家在选择一个框架时要考虑的。 -* **扩展性** +- **扩展性** 如果一个框架与内部能力强耦合,就无法移植到其他平台,或框架的支持场景单一也无法进行扩展,这样的框架很难得到外部的使用。 -* **易用性** +- **易用性** 框架的易用性体现在两个方面。第一是面向**业务开发者** ,如果一个框架在使用过程中需要让用户关注很多框架的细节,那么对研发效率要求很高的团队可能无法接受。 第二是面向**框架的二次开发者** ,他们需要对框架做一些定制支持,如果框架提供的扩展能力过于宽泛,扩展成本很高,或者可扩展的能力不够多,那么这个框架也是存在局限性的。 -* **功能的丰富度** +- **功能的丰富度** 虽然基于扩展性可以对框架进行定制,但不是所有开发者都有足够的精力做定制开发,如果框架本身对各种扩展能力提供了不同选择的支持,对于开发者来说只需要根据自己的基础设施进行组合就能在自己的环境中运行。 -* **高性能** +- **高性能** 前面三点是初期选择框架需要重点关注的指标,但随着服务规模和资源消耗变大,性能就成了不容忽视的问题。从长期的角度来说,选择框架的时候一定要关注性能,否则后续只能面临框架替换的问题,或者被迫对这个框架做定制维护。 @@ -160,7 +172,7 @@ Thrift-gen-validator 是 Thriftgo 的一个工具插件,它可以根据 Thrift #### Thrift 高性能编解码 **[Frugal][Frugal] 是一个无需生成编解码代码、基于 JIT 的高性能动态 Thrift 编解码器。** 虽然我们针对官方 Thrift 编解码已经做了优化,支持了 FastThrift,这个在我们开源前发布的优化实践里也有介绍, -但我们希望能有进一步的性能提升,参考我们开源的高性能 JSON 库 Sonic 的设计,实现了 Thrift JIT 编解码器。下图中的表格是 [Frugal][Frugal] 结合 [Kitex][Kitex] 与 FastThrift 的性能对比。 +但我们希望能有进一步的性能提升,参考我们开源的高性能 JSON 库 Sonic 的设计,实现了 Thrift JIT 编解码器。下图中的表格是 [Frugal][Frugal] 结合 [Kitex][Kitex] 与 FastThrift 的性能对比。 ![image](/img/blog/1st_RPC_Kitex/11.png) @@ -243,16 +255,16 @@ Kitex v0.4.0: https://mp.weixin.qq.com/s/ezifbQkHcZQP6MygmJABYA 本次分享主要介绍了以下内容: -* [Kitex][Kitex] 如何保持内外统一地从内部应用较广的框架转为开源框架; -* 开源一年以来发布了哪些重要的功能特性,做了哪些性能优化; -* 借助社区的力量现在 [Kitex][Kitex] 的周边生态如何、企业落地情况以及如何使用 [Kitex][Kitex] 优雅地集成内部能力。 +- [Kitex][Kitex] 如何保持内外统一地从内部应用较广的框架转为开源框架; +- 开源一年以来发布了哪些重要的功能特性,做了哪些性能优化; +- 借助社区的力量现在 [Kitex][Kitex] 的周边生态如何、企业落地情况以及如何使用 [Kitex][Kitex] 优雅地集成内部能力。 ### 展望 -* 与社区同学共建,持续丰富社区生态; -* 结合工程实践,为微服务开发者提供更多便利; -* 完善好 BDThrift 生态,持续优化 Protobuf/gRPC; -* 更多特性支持或开源,ShmIPC、QUIC、Protobuf 泛化… +- 与社区同学共建,持续丰富社区生态; +- 结合工程实践,为微服务开发者提供更多便利; +- 完善好 BDThrift 生态,持续优化 Protobuf/gRPC; +- 更多特性支持或开源,ShmIPC、QUIC、Protobuf 泛化… [Kitex]: https://github.com/cloudwego/kitex [Frugal]: https://github.com/cloudwego/frugal diff --git a/content/zh/blog/news/1st_httpHertz/index.md b/content/zh/blog/news/1st_httpHertz/index.md index 9dd9193593..7d6aa69a20 100644 --- a/content/zh/blog/news/1st_httpHertz/index.md +++ b/content/zh/blog/news/1st_httpHertz/index.md @@ -3,7 +3,7 @@ date: 2022-09-27 title: "助力字节降本增效,大规模企业级 HTTP 框架 Hertz 设计实践" projects: ["Hertz"] linkTitle: "助力字节降本增效,大规模企业级 HTTP 框架 Hertz 设计实践" -keywords: ["Hertz", "HTTP", "Golang", "Gin", "高性能","可扩展"] +keywords: ["Hertz", "HTTP", "Golang", "Gin", "高性能", "可扩展"] description: "本文描述了字节跳动内部的大规模企业级 HTTP 框架 Hertz 的设计实践,包括 Hertz 的项目起源、架构设计、功能特性,性能表现等方面。" author: welkeyever --- @@ -32,19 +32,19 @@ author: welkeyever 2017 - 2019 年期间,也就是 Ginex 发布之后,问题逐渐显现。主要有以下几点: -* **迭代受开源项目限制** +- **迭代受开源项目限制** Ginex 是一个基于 Gin 的开源封装,所以它本身在迭代方面是受到一些限制的。一旦有针对公司级的需求开发,以及 Bugfix 等等,我们都需要和开源框架 Gin 做联合开发和维护,这个周期不能完全由我们自己控制。 -* **代码混乱膨胀、维护困难** +- **代码混乱膨胀、维护困难** 由于我们和业务同学共同开发和维护 Ginex 框架,因此我们对于控制整个框架的走向没有完全的自主权,从而导致了整体代码混乱膨胀,到后期我们发现越来越难维护。 -* **无法满足性能敏感业务需求** +- **无法满足性能敏感业务需求** 另外,我们能用 Gin 做的性能优化非常少,因为 Gin 的底层是基于 Golang 的一个原生库,所以如果我们要做优化,需要在原生库的基础上做很多改造,这个其实是非常困难的。 -* **无法满足不同场景的功能需求** +- **无法满足不同场景的功能需求** 我们内部逐渐出现了一些新的场景,因此会有对 HTTP Client 的需求,支持 Websocket、支持 HTTP/2 以及支持 HTTP/3 等等需求,而在原生的 Ginex 上还是很难扩展的这些功能需求。 @@ -65,15 +65,15 @@ Ginex 是一个基于 Gin 的开源封装,所以它本身在迭代方面是受 第一章节的内容总结如下: -* **早期基于开源框架封装** +- **早期基于开源框架封装** 基于早期开源的 Golang HTTP 框架,实现了 Ginex 的封装。 -* **随着实践发展,问题逐渐出现** +- **随着实践发展,问题逐渐出现** 框架混乱膨胀,框架的维护越来越困难,业务的新需求无法得到很好地满足。 -* **为了解决问题出现基于另外的开源框架魔改的萌芽** +- **为了解决问题出现基于另外的开源框架魔改的萌芽** 我们需要思考如何跳出魔改的怪圈,把字节内部的企业级框架做得更好。 @@ -85,16 +85,16 @@ Ginex 是一个基于 Gin 的开源封装,所以它本身在迭代方面是受 为了跳出魔改的怪圈,我们决定从以下三个方面开始着手。 -* **自主研发** +- **自主研发** 既然 Ginex 是因为基于开源框架 Gin,没法做一些灵活的控制,那我们就改为完全自主研发框架。自主研发框架的代码全链路自主可控,也可以避免引入任何三方不可控因素,这样我们能够对自己的框架有一个比较完备的掌控力。 -* **质量控制** +- **质量控制** 下图列举了一些常规的质量控制手段。我要着重强调的是模糊测试,模糊测试在字节内部是广泛应用于 [Hertz][Hertz] 框架的稳定性测试中。它的核心点在于 **通过一系列的模拟服务,尝试模拟出线上用户在使用我们的框架时, 实际遇到的一些场景和使用方式** 。然后通过一些随机的算法,生成尽可能复杂、覆盖各种 Case 的场景,这可以让我们 **检测出一些潜在的问题** 。这套测试也在 [Hertz][Hertz] 早期的质量建设中,帮助我们将一些问题防患于未然。 -* **严格准入** +- **严格准入** 既然 Ginex 的问题是大家都在向里面写入内容,那么我们可以控制入口,建立一套完备的需求开发以及 Review 的闭环,控制迭代的整体流程,从而控制代码准入。同时我们配备统一的需求管理以及严格的发版准入规范,做一个标准的公司级别的框架。 @@ -117,13 +117,13 @@ Ginex 是一个基于 Gin 的开源封装,所以它本身在迭代方面是受 基于上一部分,我们可以进一步梳理出框架的需求痛点。**痛点**主要有两个方面: -* **多样的需求**:支撑支撑各个业务线及基础设施 (横向扩展性)。 -* **灵活的结构**:贯穿 HTTP 生命周期的掌控力 (纵向模块化)。 +- **多样的需求**:支撑支撑各个业务线及基础设施 (横向扩展性)。 +- **灵活的结构**:贯穿 HTTP 生命周期的掌控力 (纵向模块化)。 在此基础上进一步抽象出框架的 **科学发展观** : -* **聚类需求**:面向通用能力展开设计。 -* **跳出局部**:针对一些复杂问题,在更大范围内寻求最优解。 +- **聚类需求**:面向通用能力展开设计。 +- **跳出局部**:针对一些复杂问题,在更大范围内寻求最优解。 ![image](/img/blog/1st_HTTP_Hertz/7.png) @@ -133,15 +133,15 @@ Ginex 是一个基于 Gin 的开源封装,所以它本身在迭代方面是受 第二章节的内容总结如下: -* **跳出怪圈** +- **跳出怪圈** 引入“框架人”的概念,帮助大家理解框架的自研、质量控制和严格准入。 -* **痛点梳理** +- **痛点梳理** 为“框架人”注入有趣的灵魂,框架需要应对来自业务侧的多样化需求,还要保证自己的可持续性发展。 -* **框架科学发展观** +- **框架科学发展观** 需求聚类,跳出局部。 @@ -161,10 +161,10 @@ Ginex 是一个基于 Gin 的开源封装,所以它本身在迭代方面是受 基于这个逻辑,我们可以看一下 [Hertz][Hertz] 的整体架构图。如下图所示,从下往上看红线框圈住的部分,可以发现这就是上文提到的请求建立的全过程。各层的能力及作用如下: -* 传输层 Transport:抽象网络接口; -* 协议层 Protocol:解析请求,渲染响应编码; -* 路由层 Route:基于URL进行逻辑分发; -* 应用层 Application:业务直接交互,出现大量 API。 +- 传输层 Transport:抽象网络接口; +- 协议层 Protocol:解析请求,渲染响应编码; +- 路由层 Route:基于URL进行逻辑分发; +- 应用层 Application:业务直接交互,出现大量 API。 我们可以看到图中除了中间部分包含的四层,左右两侧各有两列。**右侧是通用层 Common** ,主要负责**提供通用能力、常用的日志接口、链路追踪以及一些配置处理相关的能力**等。 **左侧是 [Hertz][Hertz] 的代码生成工具 Hz,又称脚手架工具** ,它可以帮助我们在内部 **基于 IDL 快速地生成项目骨架** ,以加速业务迭代。 @@ -182,21 +182,21 @@ Ginex 是一个基于 Gin 的开源封装,所以它本身在迭代方面是受 那么基于 [Hertz][Hertz] 的架构设计,应该如何展开易用性和可扩展性呢?下图是 [Hertz][Hertz] 架构主要四个层级的抽象。 -* **应用层** +- **应用层** 应用层提供了一些通用能力,包括**绑定请求、响应渲染、服务发现/注册/负载均衡以及服务治理**等等。其中,**洋葱模型中间件**的核心目的是让业务开发同学**基于这个中间件快速地给业务逻辑进行扩展**, 扩展方式是可以在业务逻辑处理前和处理后分别插桩埋点做相应处理。一些比较有代表性的应用,包括日志打点、前置的安全检测,都是通过洋葱模型中间件进行处理的。 -* **路由层** +- **路由层** 路由层也是非常通用的,主要提供**静态路由、参数路由、为路由配置优先级以及路由修复**的能力,如果我们的路由层没办法满足用户需求, 它还能支撑用户做**自定义路由**的扩展。但实际应用中这些路由能力完全能够满足绝大多数用户的需求。 -* **协议层** +- **协议层** -[Hertz][Hertz] 同时提供 **HTTP/1.1** 和 **HTTP/2**,**HTTP/3** 也是我们在建设中的能力,我们还会提供 **Websocket 等 HTTP 相关的多协议支持** ,以及支持完全由业务决定的**自定义协议层扩展** 。 +[Hertz][Hertz] 同时提供 **HTTP/1.1** 和 **HTTP/2**,**HTTP/3** 也是我们在建设中的能力,我们还会提供 **Websocket 等 HTTP 相关的多协议支持** ,以及支持完全由业务决定的**自定义协议层扩展** 。 -* **传输层** +- **传输层** 目前我们已经内置了两个高性能的传输层实现。一个是**基于 CloudWeGo 开源的高性能网络库 [Netpoll][Netpoll]** 的传输层扩展,另一个是支持**基于标准库**的传输层扩展。此外,我们也同样能支持在传输层上进行**自定义传输层协议扩展** 。 @@ -224,9 +224,9 @@ Ginex 是一个基于 Gin 的开源封装,所以它本身在迭代方面是受 对于上述问题,其实有一些可能的解决方法: -* 直接利用 bufio.Reader 的局限当做 Feature,通过 buffer 大小作为 Header 大小的限制。如果超出这个大小,Header 直接解析报错,这也是 Fasthttp 的做法。 +- 直接利用 bufio.Reader 的局限当做 Feature,通过 buffer 大小作为 Header 大小的限制。如果超出这个大小,Header 直接解析报错,这也是 Fasthttp 的做法。 但实际上超出 buffer 长度后报错会导致我们没办法处理这部分请求,从而导致框架 **功能受限** 。 -* header 解析带状态,暂存中间数据,通过在上层堆叠额外复杂度的方式突破 bufio 本身的限制。但是暂存中间态会涉及到一些内存的拷贝,必然会导致 **性能受限** 。 +- header 解析带状态,暂存中间数据,通过在上层堆叠额外复杂度的方式突破 bufio 本身的限制。但是暂存中间态会涉及到一些内存的拷贝,必然会导致 **性能受限** 。 #### 真实使用环境复杂多变 @@ -268,15 +268,15 @@ CloudWeGo 公众号曾发布关于字节跳动服务网格控制面的文章, 第三章节的内容总结如下: -* **分层抽象** +- **分层抽象** 解构 HTTP 框架,分层解耦。 -* **易用可扩展** +- **易用可扩展** 提供了更丰富 API 和足够灵活的拓展能力,在每一层抽象中都提供了一个足够灵活的扩展能力应对可能的需求。 -* **自主可控的高性能探索** +- **自主可控的高性能探索** 自适应 buffer,零拷贝解析,未来将会进行更多的高性能探索。 @@ -288,10 +288,10 @@ CloudWeGo 公众号曾发布关于字节跳动服务网格控制面的文章, 本次分享的主要内容总结如下: -* 字节跳动内部 Go HTTP 框架的变迁:从基于开源封装,到开启自研之路; -* 企业级 HTTP 框架的设计考量和落地思路:破圈、需求提炼、框架科学发展观; -* [Hertz][Hertz] 核心特点:分层抽象、易用可扩展、自主可控的性能探索; -* [Hertz][Hertz] 未来的规划和挑战:框架持续打磨、助力 CloudWeGo、服务更多用户。 +- 字节跳动内部 Go HTTP 框架的变迁:从基于开源封装,到开启自研之路; +- 企业级 HTTP 框架的设计考量和落地思路:破圈、需求提炼、框架科学发展观; +- [Hertz][Hertz] 核心特点:分层抽象、易用可扩展、自主可控的性能探索; +- [Hertz][Hertz] 未来的规划和挑战:框架持续打磨、助力 CloudWeGo、服务更多用户。 最后欢迎对 [Hertz][Hertz] 感兴趣的同学积极参与到 CloudWeGo 社区中,我们一起完善 [Hertz][Hertz],共同建设 CloudWeGo! diff --git a/content/zh/blog/news/2nd_Kitex_retrospect/index.md b/content/zh/blog/news/2nd_Kitex_retrospect/index.md index 944402cd48..436320c25a 100644 --- a/content/zh/blog/news/2nd_Kitex_retrospect/index.md +++ b/content/zh/blog/news/2nd_Kitex_retrospect/index.md @@ -3,7 +3,19 @@ date: 2023-11-30 title: "Kitex 两周年回顾 — 能力升级、社区合作与未来展望" projects: ["Kitex"] linkTitle: "Kitex 两周年回顾 — 能力升级、社区合作与未来展望" -keywords: ["Kitex", "CloudWeGo", "RPC", "开源", "Golang", "DynamicGo", "Frugal", "GLS", "Dubbo", "配置中心"] +keywords: + [ + "Kitex", + "CloudWeGo", + "RPC", + "开源", + "Golang", + "DynamicGo", + "Frugal", + "GLS", + "Dubbo", + "配置中心", + ] description: "本文介绍了高性能 RPC 框架 Kitex 过去一年在性能、功能、易用性以及社区合作项目的进展。" author: Felix021 --- @@ -13,7 +25,9 @@ author: Felix021 今天的分享主要分成三个部分,首先是 [Kitex][Kitex] 的能力升级,看一下过去一年在**性能**、**功能**和**易用性**这个方面上的一些进展。第二个是社区合作项目的进展,特别是其中两个重点项目 **Kitex-Dubbo 互通**以及**配置中心集成**。第三个是给大家剧透一下我们目前在做以及计划做的一些事情。 ## 能力升级 + ### 性能 + 在2021年9月,我们曾发布了一篇[字节跳动 Go RPC框架 Kitex 性能优化实践](/zh/blog/2020/05/24/%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/), 这篇文章介绍了如何通过自研网络库 [Netpoll][Netpoll]、及自研的 Thrift 编解码器 fastCodec 来优化 [Kitex][Kitex] 的性能。 @@ -22,6 +36,7 @@ author: Felix021 尽管如此,我们一直没有停止优化 Kitex 性能的尝试。在字节内部,我们已经在试验、推广一些在核心链路上的性能提升,稍后会再给各位介绍。 #### 基于 DynamicGo 的泛化调用 + 首先介绍一个已经发布的性能优化:基于 [DynamicGo][Dynamicgo] 的泛化调用。**泛化调用**是 Kitex 的一个高级特性,能够在不预先生成 SDK 代码(也就是 Kitex Client)的前提下,使用 Kitex Generic Client 直接调用目标服务的 API。 例如字节跳动内部的 接口测试工具、API 网关等,就使用了 Kitex 的泛化 Client,能够接收一个 HTTP 请求(请求体是 JSON 格式),转换成 Thrift Binary 后,发送给 Kitex Server。 @@ -29,6 +44,7 @@ author: Felix021 ![image](/img/blog/2nd_Kitex_retrospect/generic_call.jpeg) 其实现方案是依赖一个 `map[string]interface{}` 作为泛型容器,请求时先将 json 转换为 map,在基于 Thrift IDL 完成 map -> thrift 的转换;对响应的处理则反过来。 + - 这样做的好处是灵活性高,不需要依赖预先生成的静态代码,只需要有 IDL 就可以请求目标服务; - 但是其代价是性能较差,这样一个泛型容器依赖 Go 的 GC 和 内存管理,开销巨大,不仅需要分配大量内存,还需要多次数据拷贝。 @@ -41,6 +57,7 @@ author: Felix021 ![image](/img/blog/2nd_Kitex_retrospect/dynamicgo.png) 其实际原理很简单:根据解析 IDL 生成类型描述符 Descriptor,执行如下协议转换过程 + 1. 每次从 JSON 字节流中读取一个 Key/Value pair; 2. 根据 IDL Descriptor 里找到 key 对应的 Thrift 字段; 3. 按相应类型的 Thrift 编码规范完成 Value 的编码,并写入输出字节流; @@ -49,6 +66,7 @@ author: Felix021 [DynamicGo][Dynamicgo] 除了可以优化 JSON/Thrift 的协议转换,还提供了 Thrift DOM 方式用于优化数据编排场景的性能。例如抖音某业务团队需要擦除请求中的违规数据,但仅限请求中的某一个字段;使用 DynamicGo 的 Thrift DOM API 就非常适合,可以实现 10 倍的性能提升,详情可参考 DynamicGo 的文档,这里就不展开了。 #### Frugal - 基于 JIT 的高性能 Thrift 编解码器 + [Frugal][Frugal] 是一个 基于 **JIT** 编译技术的高性能 Thrift 编解码器。 Thrift 官方以及 Kitex 默认的编解码器都是基于解析 Thrift IDL,生成相应的编解码 Go 代码。通过 JIT 技术,我们能够在**运行时动态生成**性能更好的编解码代码: @@ -68,12 +86,14 @@ Thrift 官方以及 Kitex 默认的编解码器都是基于解析 Thrift IDL, 其实 Frugal 去年就已经发布了,但是当时的早期版本覆盖不够充分。今年我们重点优化了它的稳定性,修复了所有已知问题, 最近发版的 v0.1.12 版本,可以稳定地使用在生产业务上。例如字节跳动电商业务线,某服务的峰值 QPS 约 25K,已经全量切换到 Frugal,稳定运行了数月。 -[Frugal][Frugal] 目前支持 Go1.16 ~ Go1.21,暂时只支持 AMD64 架构,未来也将支持 ARM64 架构;我们可能会在未来某个版本将 Frugal 作为 Kitex 的默认编解码器。 +[Frugal][Frugal] 目前支持 Go1.16 ~ Go1.21,暂时只支持 AMD64 架构,未来也将支持 ARM64 架构;我们可能会在未来某个版本将 Frugal 作为 Kitex 的默认编解码器。 ### 功能 + Kitex 在过去一年中从 v0.4.3 升级到 v0.7.2,其中 Feature 相关的 Pull Request 共有 40 多个,涵盖了**命令行工具**、**gRPC**、**Thrift 编解码**、**重试**、**泛化调用**、**服务治理配置**等多个方面,这里重点介绍几个比较重要的特性。 #### Fallback - 业务自定义降级 + 首先是 Kitex 在 v0.5.0 版本新增的 fallback 功能。 需求背景是,业务代码在 RPC 请求失败、无法获得响应时,往往需要执行一些降级策略。 @@ -91,14 +111,15 @@ Kitex 在过去一年中从 v0.4.3 升级到 v0.7.2,其中 Feature 相关的 P 初始化 client 时指定的这个方法会在每次请求结束前被调用,可以获得这次请求的 context、请求参数、响应,基于此实现自定义的降级策略,这样就把策略的实现都收敛起来了。 #### Thrift FastCodec - 支持 unknown fields + 在实际的业务场景中,一个请求链路往往涉及多个节点。 以链路 A -> B -> C -> D 为例,A 节点的某个 struct 需要通过 B、C 透传到 D 节点。在以往的实现里,如果在 A 新增一个字段,例如 `Extra`, 我需要使用**新的 IDL 重新生成所有节点的代码**,重新部署,才能在 D 节点获得 Extra 字段的值。整个流程比较复杂,更新周期也比较长,如果中间节点是其他团队的服务,还需要跨团队协调,非常吃力。 -在 Kitex v0.5.2 里,我们在自研的 fastCodec 里实现了 Unknown Fields 这个特性,可以很好地解决这个问题。 +在 Kitex v0.5.2 里,我们在自研的 fastCodec 里实现了 Unknown Fields 这个特性,可以很好地解决这个问题。 -例如同样是 A -> B -> C -> D 这个链路,B、C节点代码不变(如下图所示),在解析时,发现有个字段 id=2,在 struct 里找不到对应的字段,于是就写入这个未导出的 `_unknownFields` 字段(实际上就是一个 byte slice 的别名); +例如同样是 A -> B -> C -> D 这个链路,B、C节点代码不变(如下图所示),在解析时,发现有个字段 id=2,在 struct 里找不到对应的字段,于是就写入这个未导出的 `_unknownFields` 字段(实际上就是一个 byte slice 的别名); ![image](/img/blog/2nd_Kitex_retrospect/old_code.png) @@ -121,6 +142,7 @@ Kitex 在过去一年中从 v0.4.3 升级到 v0.7.2,其中 Feature 相关的 P 但是实际情况往往是,请求 C 服务的代码被多层包装,**ctx 的透传就容易被遗漏**;我们遇到的情况更麻烦,对 C 服务的请求是由第三方库完成的,而该库的接口就不支持传入 ctx,而这样的代码改造成本很高,可能需要协调多个团队才能完成。 为了解决这个痛点,我们引入了基于 GLS(goroutine local storage)的 session 传递机制。具体方案是: + 1. 在 Kitex Server 这边,收到请求后,先将 context 备份在 GLS 里,然后再调用 Handler ,也就是业务代码; 2. 在业务代码里调用 client 发送请求时,先检查入参的 ctx 里是否包含期望的票据,如果没有,则从 GLS 的备份里取出,再发出请求。 @@ -129,6 +151,7 @@ Kitex 在过去一年中从 v0.4.3 升级到 v0.7.2,其中 Feature 相关的 P ![image](/img/blog/2nd_Kitex_retrospect/GLS_example.png) 说明: + 1. 初始化 Server 的时候打开 `ContextBackup` 开关 2. 初始化 Client 的时候指定一个 `backupHandler` 3. 每次发出请求前,会调用该 handler,检查入参是否包含了 `LogID` @@ -140,9 +163,11 @@ Kitex 在过去一年中从 v0.4.3 升级到 v0.7.2,其中 Feature 相关的 P 由于不是同一个 goroutine,无法直接共享 Local Storage;我们借鉴 pprof 给 goroutine 染色的机制,将备份的 ctx 也传递给新的 goroutine,这样就实现了在**异步场景**也能**隐式传递票据**的能力。 ### 易用性 + 除了高性能和丰富的功能,我们也很注重提高 Kitex 的易用性。 #### 文档 + 众所皆知,程序员最讨厌的两件事:一是写文档,二是别人不写文档。因此我们很注重降低编写文档的启动成本,并努力推进文档建设。 在字节跳动内部,Kitex 的文档是以飞书知识库的形式组织的,能够更好地集成到飞书的搜索,方便字节员工查询;由于飞书文档更新方便,因此比官网文档更新更及时;新功能在开发时往往也是先在飞书知识库中撰写文档,有些没有及时同步到官网。各种原因导致内外两个分支差别越来越大。 @@ -152,6 +177,7 @@ Kitex 在过去一年中从 v0.4.3 升级到 v0.7.2,其中 Feature 相关的 P 此外,我们还在搭建一套机制,用于自动化将内部文档同步到官网,希望能让开源用户以后也能像内部用户一样得到及时更新的文档。 #### 其他优化 + 除了文档, Kitex 还做了一些其他易用性相关的工作。 我们发布了一个示例项目[笔记服务](https://github.com/cloudwego/kitex-examples/tree/main/bizdemo/easy_note),在实例中展示中间件、限流、重试、超时控制等各种特性的用法,通过真实的项目代码给 Kitex 用户提供参考。 @@ -159,13 +185,16 @@ Kitex 在过去一年中从 v0.4.3 升级到 v0.7.2,其中 Feature 相关的 P 其次我们也在努力提高问题排查的效率,例如我们根据日常 oncall 的需求,在报错信息里添加了更具体的上下文信息(诸如超时报错增加具体原因、panic 信息增加 method name、thrift 编解码错误信息增加具体字段名称等),方便快速定位到具体的问题点。 此外,Kitex 命令行工具也在持续改进。 + - 例如很多企业用户是在 Windows 上开发,之前 Kitex 无法正常在 Windows 下生成代码,导致这些用户还需要一个 Linux 环境来辅助,非常不方便,我们根据这些用户的反馈做了优化。 - 我们还实现了一个 IDL 裁剪工具,能够识别出没有被引用的结构体,在生成代码时直接过滤掉,这对于一些包浆的老项目非常有帮助。 ## 社区合作项目 + 过去的一年里,在 CloudWeGo 社区的支持下,我们也取得了很多成果,特别是 Dubbo 互通和配置中心集成这两个项目。 ### Dubbo 互通 + 虽然 Kitex 最初是一个 Thrift RPC 框架,但是其架构设计有较好的扩展性,如图所示,增加新的协议,核心工作是按 Codec 接口实现一个对应的协议编解码器(Codec 或者 PayloadCodec): ![image](/img/blog/2nd_Kitex_retrospect/kitex_transport.png) @@ -187,6 +216,7 @@ Dubbo 互通项目源于某企业用户提出的需求,他们有一些供应 ![image](/img/blog/2nd_Kitex_retrospect/kitex_dubbo.jpeg) 未来计划: + - 首先是提高与 dubbo-java 的兼容性,以及允许用户在 IDL 注解里指定对应的 Java 类型。 - 其次是与注册中心的对接。虽然 Kitex 已经有对应的注册中心模块,但具体的数据格式和 Dubbo 不一致,这块还需要一些改造,相关工作即将完成。 - 最后是性能问题,目前和 Kitex Thrift 相比有较大差距,因为 dubbo-go-hessian2 这个库完全基于反射实现,性能还有很大优化空间。计划实现 Hessian2 的 FastCodec,从而解决编解码的性能瓶颈。 @@ -196,6 +226,7 @@ Dubbo 互通项目源于某企业用户提出的需求,他们有一些供应 在此也特别向这个项目的社区贡献者 @[DMwangnima](https://github.com/DMwangnima)、@[Lvnszn](https://github.com/Lvnszn)、@[ahaostudy](https://github.com/ahaostudy)、@[jasondeng1997](https://github.com/jasondeng1997)、@[VaderKai](https://github.com/VaderKai) 等同学致谢,感谢他们抽出大量业余时间完成这个项目。 ### 配置中心集成 + 另一个社区合作的重点项目是「配置中心集成」。 Kitex 提供了可动态配置的服务治理能力,包括客户端的超时、重试、熔断,以及服务端的限流。 @@ -220,22 +251,28 @@ Kitex 提供了可动态配置的服务治理能力,包括客户端的超时 我们计划完成对接常见的配置中心,在这个 [issue](https://github.com/cloudwego/kitex/issues/973) 里有更详细的说明,欢迎大家围观。 目前的进展是: + - [file](https://github.com/kitex-contrib/config-file)、[apollo](https://github.com/kitex-contrib/config-apollo)、[etcd](https://github.com/kitex-contrib/config-etcd)、[zookeeper](https://github.com/kitex-contrib/config-zookeeper) 已经完成; - [consul](https://github.com/kitex-contrib/config-consul) 正在开发中; 感兴趣的同学的同学也可以参与进来,一起 review、测试验证这些扩展模块。 ## 未来展望 + 最后给大家剧透一下我们目前正在尝试的一些方向。 ### 合并部署 + #### 亲和性部署 + 我们之前的优化大多是针对服务内,而随着可优化点逐渐减少,我们开始考虑其他目标,比如优化 RPC 请求在网络通信上的开销。 具体的方案如下: + - 首先是亲和性调度,通过修改容器化调度机制,我们将 Client 和 Server 尽量调度到相同的物理机上; - 于是我们就可以用同机通信来降低开销。 目前我们已经实现的同机通信包括如下三种: + - **Unix Domain Socket**,比标准的 TCP Socket 性能要好一些,但不太多; - [ShmIPC](https://github.com/cloudwego/shmipc-go),基于共享内存的进程间通信,这个可以直接省略序列化数据的传递,只需要把内存地址告诉接收方即可; - 最后是 **RPAL** 这个「黑科技」,这是 Run Process As Library 的缩写,我们和字节的内核组合作,通过定制化的内核,将两个进程放在同一个地址空间,在满足一定条件的情况下,我们甚至可以不需要做序列化; @@ -243,6 +280,7 @@ Kitex 提供了可动态配置的服务治理能力,包括客户端的超时 目前我们已经在 100 多个服务上开启了这个能力,也取得了一些性能收益,对于效果比较好的服务,能够节省约 5~10% 的 CPU,耗时也能减少 10~70%;当然实际表现取决于服务的一些特性,例如数据包的大小等。 #### 编译期合并 + 另一个思路是编译期合并。 该方案的出发点是,我们发现微服务虽然提升了团队协作的效率,但是也增加了系统整体复杂性,尤其是在服务部署、资源占用、通信开销等方面。 @@ -256,9 +294,11 @@ Kitex 提供了可动态配置的服务治理能力,包括客户端的超时 以上是我们在亲和性方面的尝试。 ### 序列化 + 在序列化方面,我们也还在做一些努力和尝试。 #### Frugal - SSA Backend + 首先是 Frugal,前面介绍过它的性能已经显著优于传统的 Thrift 编解码代码,但它还有提升空间。 目前 Frugal 的实现是用 Go 直接生成对应的汇编代码。我们在具体实现中也应用了一些优化手段,例如生成更紧凑的代码,减少分支等;但光靠我们自己这样写,无法充分利用现有的编译器优化技术。 @@ -272,6 +312,7 @@ Kitex 提供了可动态配置的服务治理能力,包括客户端的超时 预计这样改造后,性能可以提升至少 30%。 #### 按需序列化 + 在另外一个探索方向是按需序列化,具体又可以分成三块。 首先是编译前。我们目前已经发布了一个 IDL 裁剪工具,能够识别出没有被引用的类型;但是被引用的类型也可能是不需要的,例如A、B两个服务依赖同一个类型,但其中有一个字段可能A需要,B不需要。我们考虑在这个工具上增加用户标注能力,允许用户指定不需要的字段,从而进一步降低序列化开销。 @@ -281,24 +322,27 @@ Kitex 提供了可动态配置的服务治理能力,包括客户端的超时 最后是编译后,在运行时,也允许业务通过指定不需要的字段,从而节省编解码的开销。 ## 总结 + 最后我们整体回顾一下: 在能力升级方面, + - [Kitex][Kitex] 通过 [DynamicGo][DynamicGo] 优化了泛化调用的性能,高性能 [Frugal][Frugal] 编解码器也已经稳定,可用于生产环境了; - 过去一年新增了 fallback 方便业务实现自定义降级策略,并通过 unknown fields 和 session 传递机制来解决长链路的改造问题; - 我们还通过文档优化、demo 项目、问题排查效率改造 和 增强命令行工具等方式提升了 Kitex 的易用性; 在社区合作方面, + - 我们通过 Kitex - Dubbo [互通项目](https://github.com/kitex-contrib/codec-dubbo)支持了 Dubbo 的 hessian2 协议,可以和 Dubbo Java、Dubbo-Go 框架互通,并且还有后续的优化,也能反哺 Dubbo 社区; - 在配置中心集成项目中,我们发布了 [Nacos](https://github.com/kitex-contrib/config-nacos) 扩展,方便用户集成,目前还在继续推进其他配置中心的对接; - + 未来还有一些探索方向, + - 在合并部署方面,我们通过亲和性部署、编译其合并这两种方式,既能保留微服务的好处,又能享受一部分单体不服务的优势; - 在序列化方面,我们还继续进一步优化 [Frugal][Frugal],并且通过编译前中后各环节来实现按需序列化的能力; 以上是在 CloudWeGo 两周年之际,关于 [Kitex][Kitex] 的回顾和展望,希望对大家有帮助,谢谢。 - [Kitex]: http://github.com/cloudwego/kitex [DynamicGo]: http://github.com/cloudwego/dynamicgo [Netpoll]: http://github.com/cloudwego/netpoll diff --git a/content/zh/blog/news/CloudWeGo_Usability_Construction/index.md b/content/zh/blog/news/CloudWeGo_Usability_Construction/index.md index 8275da8c7c..4ea337bac7 100644 --- a/content/zh/blog/news/CloudWeGo_Usability_Construction/index.md +++ b/content/zh/blog/news/CloudWeGo_Usability_Construction/index.md @@ -14,7 +14,7 @@ author: GuangyuFan ## 背景 -CloudWeGo 是一套由字节跳动基础架构服务框架团队开源的、可快速构建企业级云原生微服务架构的中间件集合。 +CloudWeGo 是一套由字节跳动基础架构服务框架团队开源的、可快速构建企业级云原生微服务架构的中间件集合。 CloudWeGo 下的项目主要有三个特点:**高性能**、**高扩展性**以及**高可靠性**;并且,在开源后我们也更加重视易用性的建设,我们意识到易用性可以给社区带来很多用户、进而形成活跃的社区氛围,推动社区持续发展,而且易用性可帮助用户快速完成业务逻辑开发,提升效率。 针对易用性,我们在研发体验、用户体验以及社区宣传等均做了诸多工作,下面我来一一介绍。另外这次分享主要会重点介绍 [Hertz][Hertz] 以及围绕 [cwgo][cwgo] 的易用性建设。 @@ -25,18 +25,20 @@ CloudWeGo 下的项目主要有三个特点:**高性能**、**高扩展性** 第二个问题是框架的脚手架工具较多,例如 CloudWeGo 下就有 hz 和 kitex 两个脚手架,这无疑增加了用户的学习成本;第三个问题是文档的问题,我们在 issue 和用户群的用户反馈中看出,目前我们的文档存在描述不清晰,内容缺失等问题,导致用户遇到问题,往往无法快速解决。 针对以上问题,我们开发了多种能力以快速支持用户需求。 -1. **多协议支持**:首先需要介绍的是 Hertz 可支持无缝切换多协议,目前一些开源的框架已经支持了 h2/h3 协议了,因此我们基于 Hertz 协议层的拓展能力,完成了 http2/http3 的实现,并放到了 hertz-contrib 下。其使用方式非常简单,只需要在 Hertz engine 上将对应的协议注册上就可以啦。 http3 协议的支持也类似,不过我们需要将传输层指定为 Hertz 拓展的 quic 协议的传输层,其他的操作就和 http2 一样了。 + +1. **多协议支持**:首先需要介绍的是 Hertz 可支持无缝切换多协议,目前一些开源的框架已经支持了 h2/h3 协议了,因此我们基于 Hertz 协议层的拓展能力,完成了 http2/http3 的实现,并放到了 hertz-contrib 下。其使用方式非常简单,只需要在 Hertz engine 上将对应的协议注册上就可以啦。 http3 协议的支持也类似,不过我们需要将传输层指定为 Hertz 拓展的 quic 协议的传输层,其他的操作就和 http2 一样了。 ![image](/img/blog/CloudWeGo_Usability_Construction/multi_protocols.png) 2. **Response Writer 劫持**:接下来,再给大家介绍一下 Response Writer 劫持能力。在介绍 Writer 劫持前,先说一下 Hertz 读写报文的流程(图中数字部分),Hertz 会先在连接中读数据&解析,然后会根据请求内容进行路由匹配、业务逻辑处理、创建响应数据等,并在这些工作结束后,由框架将数据发送给对端。这么做可完全简化用户操作,不过在一些场景下却存在问题,首先是用户无法控制响应真正 flush 到对端的时机,因此在一些增量生成数据、实时性要求高的场景,用户限制较多。 ![image](/img/blog/CloudWeGo_Usability_Construction/response_writer.png) - 因此,我们开发了 Response Writer 劫持能力,在原来写响应流程的基础之上,支持用户在业务 handler/中间件中劫持 Response Writer,提前将响应数据发回到对端,实现更加灵活的写请求方式。 我们已经基于 Response Writer 的能力实现了 handler flush、SSE、流式 Gzip 等能力,更多能力也期待大家贡献。 + 因此,我们开发了 Response Writer 劫持能力,在原来写响应流程的基础之上,支持用户在业务 handler/中间件中劫持 Response Writer,提前将响应数据发回到对端,实现更加灵活的写请求方式。 我们已经基于 Response Writer 的能力实现了 handler flush、SSE、流式 Gzip 等能力,更多能力也期待大家贡献。 3. 参数绑定重构:介绍完 Writer 劫持后,再来给大家介绍一个重要的 Feature - 参数绑定。重构之前 Hertz 的参数绑定依赖了第三方的实现,这会存在以下问题: + - 依赖第三方实现,用户的需求需要诉诸于开发者 - 提供接口较少,迁移过来的同学会增加学习成本 - 性能差,之前的实现适配的是标准 http 库的存储模型,Hertz 用需要多一次转换,性能差 - + 为解决这些问题,我们重构了参数绑定的能力,将其实现放到 Hertz 内部,作为我们应用层的一个重要实现,重构后它支持和之前一样的绑定规则和使用方法,并且性能也会完全优于之前。另外还支持了自定义 binder 和 Validator,方便用户使用其熟悉的语法。另外,我们将所有的配置统一收敛到一个结构体,使用 withOption 的形式注入到 Hertz engine 上。 以上 3 个就是 [Hertz][Hertz] 比较重要的易用性建设方面的 Feature。 @@ -76,13 +78,15 @@ Client 端生成的目的主要是可以屏蔽掉初始化 Hertz client 、发 ![image](/img/blog/CloudWeGo_Usability_Construction/cwgo.png) 此外,目前 CloudWeGo 社区的 Go 项目还面临如下问题: + 1. API 管理能力相对薄弱, IDL 本身能够作为接口描述/定义工具贯穿整个业务开发迭代过程,但实际 CloudWeGo 对外并没有一个明确的实践方案,目前和企业用户对接时基本上是要求业务方自行围绕 IDL 进行 API 相关的管理 2. 各个组件相对独立,在共同使用的时候不能无缝的配合 3. 缺少常用的单测、DB 等代码的生成及配置 -随着未来 CloudWeGo 开源组件不断增多,零碎的用户体验也会不断地割裂,因此我们发布了 CloudWeGo all in one 工具 cwgo,旨在从一个全局的视角去解决以上问题。提供一个更简单、易用的微服务生成、管理形式。 +随着未来 CloudWeGo 开源组件不断增多,零碎的用户体验也会不断地割裂,因此我们发布了 CloudWeGo all in one 工具 cwgo,旨在从一个全局的视角去解决以上问题。提供一个更简单、易用的微服务生成、管理形式。 下面来介绍 cwgo 的几个特性 + 1. cwgo 集成了 hz/kitex 脚手架的能力,并将他们的命令进行抽象、简化,统一在 cwgo 工具上展示,并且会打通生成的结构体、注解、Validator 等功能,无论用户使用 RPC 还是 HTTP,都能为用户提供一个统一的生成代码体验 2. 交互式命令行,这个能力注意是面向初阶用户,以交互式的形式为用户生成目标代码,极大减少学习成本,用户只需要点点点就可以完成微服务的生成。 3. 我们会生成更加服务企业需求的 mvc 模版,如右图所示,协助业务的快速开发落地,并方便日后的迭代及维护;并且,cwgo 支持自定义模版、模版托管等能力,也更便于完成模板的管理以及快速替换。 @@ -95,6 +99,7 @@ Client 端生成的目的主要是可以屏蔽掉初始化 Hertz client 、发 自从开源来,CloudWeGo 下的项目一直都注重文档的问题,但是每次都是哪里有问题修哪里,无法全面解决问题 因此,我们参与 CCF GLCC 项目发起了文档优化专项的工作,在该专项中我们主要做了以下工作: + 1. 全方位地对文档进行重新体验,包括代码、图片、内容等,并记录相关问题 2. 根据记录的相关问题,我们有专人来对文档进行优化,解决了一些逻辑混乱、描述不清晰等问题,并着重优化了 新人教程、Hertz 核心能力等常用文档。根据反馈,优化后的文档已经可以解决基本所有常见问题 3. 此外,我们还对文档格式、目录结构进行了统一的调整,提供更好的视觉体验 @@ -107,6 +112,7 @@ Client 端生成的目的主要是可以屏蔽掉初始化 Hertz client 、发 目前,我们提供了 [hertz-example](https://github.com/cloudwego/hertz-examples)、[kitex-example](https://github.com/cloudwego/kitex-examples) 代码库,这里包含了所有常用 Feature 的可执行的使用实例,并且定期更新、维护。 另外,为了使得业务更快地能使用 CloudWeGo 项目完成业务逻辑开发,我们提供了若干个真实场景的 demo,目前提供了如下的 demo,其中下面的几个业务代码都是使用了 Hertz 和 Kitex 进行开发或者重构,大家可以在此基础上拓展自己的业务逻辑,完成业务的快速上线。 + 1. [Bookinfo](https://github.com/cloudwego/biz-demo/tree/main/bookinfo): 使用 Hertz+Kitex 重新实现 IstioBookinfo 2. [Easy Note](https://github.com/cloudwego/biz-demo/tree/main/easy_note): 使用 Hertz+Kitex 微服务的形式实现一个笔记服务 3. [Book Shop](https://github.com/cloudwego/biz-demo/tree/main/book-shop): 使用 Hertz+Kitex 实现一个电商示例 @@ -119,7 +125,9 @@ Client 端生成的目的主要是可以屏蔽掉初始化 Hertz client 、发 截止目前,CSG 活动已经举办了 5 期,分别带大家了解了 Hertz/kitex/volo 框架的诸多源码和最佳实践,帮助开发者更好的了解和使用框架。大家可以在 [cloudwego/community](https://github.com/cloudwego/community) 仓库的 issue 查看往期活动的 issue 介绍与回放。 ## 展望 + 未来,我们还将继续对 CloudWeGo 的易用性进行持续性的投入和打磨,为用户提供更好的研发体验 + 1. 通用研发流程:为用户一套可直接使用的企业级研发流程,并协作各个框架,完成业务高效开发全流程 - API 一站式管理:统一 CloudWeGo 项目的 API 管理方式,一站式完成描述、开发、测试全流程 - 分布式 IDL 管理:IDL& 产物与业务代码分开管理,降低维护成本 diff --git a/content/zh/blog/news/Hertz_Benchmark/index.md b/content/zh/blog/news/Hertz_Benchmark/index.md index 5905095e52..94bfbade3e 100644 --- a/content/zh/blog/news/Hertz_Benchmark/index.md +++ b/content/zh/blog/news/Hertz_Benchmark/index.md @@ -18,18 +18,18 @@ author: Duslia [Hertz][Hertz] 诞生于字节跳动大规模微服务架构实践,面向的场景自然是微服务场景,因此下面会先介绍微服务 HTTP 场景的特点,方便开发者深入理解 [Hertz][Hertz] 的设计思考。 -* **HTTP 通信模型** +- **HTTP 通信模型** 微服务间的通信通常以 Ping-Pong 模型为主,除了常规的吞吐性能指标外,每次 HTTP 的**平均时延**也是开发者需要考虑的点。吞吐达到瓶颈时可以通过增加机器快速解决,但对用户使用体验有显著影响的时延却没有那么容易降低。 在微服务场景下,一次调用往往需要多个微服务协作完成,即使每个节点延迟很低,最终汇聚到链路上的时延也会被放大,因此微服务场景下时延指标是开发者更应该关注的点。[Hertz][Hertz] 在保证吞吐的前提下,也针对时延做了一定优化。 -* **长短连接使用** +- **长短连接使用** 由于 TCP 连接首次建立时需要三次握手,如果每个请求都建立新连接,这部分的开销是非常大的。因此对于时延敏感型服务,尽量使用长连接完成请求。在 HTTP 1.1 中,长连接也是默认的选项。 但是没有银弹,维持连接也需要消耗资源,长连接的水平扩展能力也不如短连接。因此,在某些场景下并不适合使用长连接,比如定时拉取配置的场景, 在这个场景下,建连时延对配置影响并不大,且当配置中心负载过高时,希望能够方便的进行水平扩容,这时短连接可能是一个更好的选择。 -* **包体积大小** +- **包体积大小** 一个服务的包大小取决于实际的业务场景。HTTP 场景的数据可以放在 query、path、header、body 等地方,不同位置对解析造成的影响也不一样。 HTTP 的 header 是标识符协议,在没有找到特定的标识符之前,框架并不知道 header 还有多少,因此框架需要收到全部的 header 后才能够解析完成,对框架的内存模型不很友好。 @@ -37,7 +37,7 @@ HTTP 的 header 是标识符协议,在没有找到特定的标识符之前, 同时在字节跳动内部线上服务的统计中,发现大部分包在 1K 以内(但是太小的包没有实际意义,比如固定返回 "hello world"),同时大包场景上不封顶,各个包大小均有涉及,所以 [Hertz][Hertz] 在最常用的 128k 以内的包的性能(吞吐和时延)进行了重点优化。 -* **并发数量** +- **并发数量** 每个实例的上游可能会有很多个,不会只接受某个实例的请求;而且,HTTP 1 的连接不能够多路复用,每条连接上只能同时处理一个请求。因此 Server 需要接受多个连接同时处理。 不同服务的连接使用率也不同,比如压测服务的连接使用率很高,一个请求完成后马上就会进行下一个请求;有的服务连接使用率很低,虽然是长连接,但是只使用一次。这两者使用的连接模型并不相同, @@ -51,10 +51,10 @@ Github 上的压测项目有很多,网络上也有很多性能测试报告, 在进行压测前,应考虑自己真正的使用场景,比如: -* **长短连接的使用** :使用长连接还是短连接更符合自己的场景。 -* **连接使用率的估算** :如果使用长连接,且连接使用率很高(大部分场景),则使用默认配置即可;如果连接使用率很低,可以添加配置:**`server.WithIdleTimeout(0)`**,将 goroutine per connection 的模型修改为协程池模型,并进行对比测试。 -* **数据位置及大小的确定** :上面提到不同位置(如 query、header、body 等)及大小的数据对框架可能造成影响,如果所有框架的性能都比较一般,可以考虑换一个数据传输位置。 -* **并发数的确定** :有的服务属于轻业务重框架,这个时候框架的并发可能会很高;有的服务属于重业务轻框架,这个时候框架的并发可能会很低。 +- **长短连接的使用** :使用长连接还是短连接更符合自己的场景。 +- **连接使用率的估算** :如果使用长连接,且连接使用率很高(大部分场景),则使用默认配置即可;如果连接使用率很低,可以添加配置:**`server.WithIdleTimeout(0)`**,将 goroutine per connection 的模型修改为协程池模型,并进行对比测试。 +- **数据位置及大小的确定** :上面提到不同位置(如 query、header、body 等)及大小的数据对框架可能造成影响,如果所有框架的性能都比较一般,可以考虑换一个数据传输位置。 +- **并发数的确定** :有的服务属于轻业务重框架,这个时候框架的并发可能会很高;有的服务属于重业务轻框架,这个时候框架的并发可能会很低。 如果只是想看一下框架的性能,可以使用常规的场景:**长连接、较高连接使用率、1k body、100 并发**等。[hertz-benchmark][hertz-benchmark] 仓库默认的压测配置也是如此。 同时 [hertz-benchmark][hertz-benchmark] 仓库也开发给用户 header、body、并发数的配置,用户可以方便的修改这些配置完成贴合自己的压测。 @@ -80,14 +80,15 @@ Github 上的压测项目有很多,网络上也有很多性能测试报告, 在满足上述要求的前提下,我们基于当前最新版本对多个框架进行了压测对比,压测代码在 [hertz-benchmark][hertz-benchmark] 仓库。 在充分压满 Server 的目标下,[Hertz][Hertz] 的 P99 延迟在所有压测框架中最低,吞吐也是属于第一梯队,且在持续优化中。 -* CPU: AMD EPYC 7Y83 64-Core Processor 2.7GHz - * 运行限定 server 4-CPUs,client 16-CPUS -* OS:Debian GNU/Linux 10 (buster) -* Go 1.19 -* [hertz v0.3.2](https://github.com/cloudwego/hertz/releases/tag/v0.3.2),[fasthttp v1.40.0](https://github.com/valyala/fasthttp/releases/tag/v1.40.0), +- CPU: AMD EPYC 7Y83 64-Core Processor 2.7GHz + - 运行限定 server 4-CPUs,client 16-CPUS +- OS:Debian GNU/Linux 10 (buster) +- Go 1.19 +- [hertz v0.3.2](https://github.com/cloudwego/hertz/releases/tag/v0.3.2),[fasthttp v1.40.0](https://github.com/valyala/fasthttp/releases/tag/v1.40.0), [gin v1.8.1](https://github.com/gin-gonic/gin/releases/tag/v1.8.1),[fiber v2.38.1](https://github.com/gofiber/fiber/releases/tag/v2.38.1) ![image](/img/blog/Hertz-benchmark/1.png) +

四个框架的吞吐和时延比较

![image](/img/blog/Hertz-benchmark/2.png) diff --git a/content/zh/blog/news/Hertz_Open_Source/index.md b/content/zh/blog/news/Hertz_Open_Source/index.md index e34fbe9f0b..884d5d8178 100644 --- a/content/zh/blog/news/Hertz_Open_Source/index.md +++ b/content/zh/blog/news/Hertz_Open_Source/index.md @@ -29,23 +29,23 @@ author: CloudWeGo 下面是 [Hertz][Hertz] 的一些特性: -* **稳定性** +- **稳定性** [Hertz][Hertz] 在如此大规模的场景下,每一个 PR 的合入、每一次发版都要慎之又慎,稍有不慎便可能造成千万甚至更多的损失。我们制定了规范的 PR、发版流程,每次合入代码需要由有经验的同学审核。 即便如此,为了降低风险,我们也搭建了各种测试场景,包括兼容性、高并发、大小包等场景,每次的 PR、发版都需要测试一段时间,充分测试,将每次发版的风险减少到最低。 -* **高易用性** +- **高易用性** 在开发过程中,快速写出正确的代码往往是重要的。[Hertz][Hertz] 在设计 API 时,考虑到用户的使用习惯,参考业界主流框架使用 API 的方式,并加以优化。在 [Hertz][Hertz] 在迭代过程中,积极听取用户意见,持续打磨框架, 比如很多用户希望 Client 也有 Trace 的能力,为此,[Hertz][Hertz] Client 支持了中间件能力;在代理场景中,[Hertz][Hertz] Client 也支持了流式处理。 在做中间件和流式处理设计时,也考虑到用户实际使用习惯,帮助用户更快地写出正确的代码。[Hertz][Hertz] 也提供了命令行工具,一键生成代码,提高框架的易用性。 -* **易扩展** +- **易扩展** [Hertz][Hertz] 采用了分层设计,提供了较多的接口以及默认的扩展实现,用户也可以自行扩展,详情可参考 CloudWeGo 官网的 [Hertz][Hertz] 扩展部分。 同时得益于框架的分层设计,框架的扩展性也会大很多。目前仅将稳定的能力开源给社区,更多的规划参考 RoadMap。 -* **低延时** +- **低延时** [Hertz][Hertz] 默认使用自研的高性能网络库 [Netpoll][Netpoll],在一些特殊场景中,相较于 go net,[Hertz][Hertz] 在 QPS、时延上均具有一定优势。关于性能数据,可参考下图 Echo 数据。 在内部实践中,某些典型服务,如框架占比较高的服务、网关等服务,迁移 [Hertz][Hertz] 后相比 Gin 框架,资源使用显著减少,**CPU 使用率随流量大小降低 30%—60%。** @@ -53,7 +53,7 @@ author: CloudWeGo ![image](/img/blog/Hertz_Open_Source/Echo.png) - * **命令行工具** + - **命令行工具** [Hertz][Hertz] 提供了一个简单易用的命令行工具 Hz,用户只需提供一个 IDL,根据定义好的接口信息,Hz 便可以一键生成项目脚手架,开箱即用使用 [Hertz][Hertz];Hz 也提供更新能力,用户的 IDL 如果发生改变,Hz 可以更新脚手架。 目前 Hz 支持了 Thrift 和 Protobuf 两种 IDL 定义。命令行工具内置丰富的选项,可以根据自己的需求使用。 @@ -79,11 +79,11 @@ author: CloudWeGo 如前文所述,目前 [Hertz][Hertz] 只开源了内部经过稳定性验证的部分,未来,我们会进一步推动其走向完善: -* **云原生能力支持**。支持 xDS API,从 Istio 动态获取服务配置。 -* **多协议的支持**。[Hertz][Hertz] 目前只开源了 HTTP1 的部分,未来我们还会开源其他协议,如:HTTP2、Websocket、ALPN 等,为开发者提供更多场景的微服务需求支持。如果有需求也可以提交 issue 告诉我们,让我们知道您的需求以便快速支持。 -* **更好用的命令行工具**。我们将继续迭代 Hz,持续集成各种常用的中间件,提供模块化构建能力,用户可以按需选择所需组件。 -* **更完善的生态支持**。由于 [Hertz][Hertz] 没有采用 go net 的数据结构,需要更多的生态支持。第一批开源我们只开源了 CORS、Trace、Metrics 等生态。未来我们还将支持包括反向代理、Session 等生态。 -* **结合内外部用户需求,持续迭代**。项目开源后,我们也会根据开发者需求开展迭代。 +- **云原生能力支持**。支持 xDS API,从 Istio 动态获取服务配置。 +- **多协议的支持**。[Hertz][Hertz] 目前只开源了 HTTP1 的部分,未来我们还会开源其他协议,如:HTTP2、Websocket、ALPN 等,为开发者提供更多场景的微服务需求支持。如果有需求也可以提交 issue 告诉我们,让我们知道您的需求以便快速支持。 +- **更好用的命令行工具**。我们将继续迭代 Hz,持续集成各种常用的中间件,提供模块化构建能力,用户可以按需选择所需组件。 +- **更完善的生态支持**。由于 [Hertz][Hertz] 没有采用 go net 的数据结构,需要更多的生态支持。第一批开源我们只开源了 CORS、Trace、Metrics 等生态。未来我们还将支持包括反向代理、Session 等生态。 +- **结合内外部用户需求,持续迭代**。项目开源后,我们也会根据开发者需求开展迭代。 欢迎大家向 [Hertz][Hertz] 提交 issue 和 PR 一起来共建。 @@ -91,9 +91,9 @@ author: CloudWeGo ## 04 相关链接 -* 项目地址: https://github.com/cloudwego/hertz +- 项目地址: https://github.com/cloudwego/hertz -* 周边生态: https://github.com/hertz-contrib +- 周边生态: https://github.com/hertz-contrib [Hertz]: https://github.com/cloudwego/hertz [Kitex]: https://github.com/cloudwego/kitex diff --git a/content/zh/blog/news/Hertz_Stream_Based_Design/index.md b/content/zh/blog/news/Hertz_Stream_Based_Design/index.md index f7b21abb37..55c0348ea4 100644 --- a/content/zh/blog/news/Hertz_Stream_Based_Design/index.md +++ b/content/zh/blog/news/Hertz_Stream_Based_Design/index.md @@ -3,7 +3,7 @@ date: 2023-08-02 title: "Hertz 支持 QUIC & HTTP/3" projects: ["Hertz"] linkTitle: "Hertz 支持 QUIC & HTTP/3" -keywords: ['Go', 'Hertz', 'QUIC', 'HTTP/3', '接口设计'] +keywords: ["Go", "Hertz", "QUIC", "HTTP/3", "接口设计"] description: "本文介绍了 Hertz 为支持 QUIC & HTTP/3 在网络传输层和协议层提供的接口设计方案。" author: CloudWeGo --- @@ -58,30 +58,30 @@ type Conn interface { type Reader interface { // Peek returns the next n bytes without advancing the reader. Peek(n int) ([]byte, error) - + // Skip discards the next n bytes. Skip(n int) error - + // Release the memory space occupied by all read slices. This method needs to be executed actively to // recycle the memory after confirming that the previously read data is no longer in use. // After invoking Release, the slices obtained by the method such as Peek will // become an invalid address and cannot be used anymore. Release() error - + // Len returns the total length of the readable data in the reader. Len() int - + // ReadByte is used to read one byte with advancing the read pointer. ReadByte() (byte, error) - + // ReadBinary is used to read next n byte with copy, and the read pointer will be advanced. ReadBinary(n int) (p []byte, err error) } - + type Writer interface { // Malloc will provide a n bytes buffer to send data. Malloc(n int) (buf []byte, err error) - + // WriteBinary will use the user buffer to flush. // NOTE: Before flush successfully, the buffer b should be valid. WriteBinary(b []byte) (n int, err error) @@ -116,20 +116,20 @@ TCP 的网络/协议层抽象当中来。 ##### 方案 A -基于上述分层思想,一个和网络传输层 Serve 相对应的 QUIC 抽象其实就出具雏形了,命名为 OnStream,语义和 Serve 基本一致* +基于上述分层思想,一个和网络传输层 Serve 相对应的 QUIC 抽象其实就出具雏形了,命名为 OnStream,语义和 Serve 基本一致\* :当流完成准备。具体需要提供的实现就是上层协议(这里是 HTTP/3)。 ```go type ServeStream func(ctx context.Context, stream Stream) error ``` -*注:ServeStream 语义和 Serve 一致具体指 HTTP/1 的 Serve 对应的其实就是“下一个请求的数据已经准备好”;通过实现该接口就可以完成协议处理。 +\*注:ServeStream 语义和 Serve 一致具体指 HTTP/1 的 Serve 对应的其实就是“下一个请求的数据已经准备好”;通过实现该接口就可以完成协议处理。 如果进一步深入,其实和当前 Hertz HTTP/2 的实现其实并不完全对应,究其原因在于: 1. HTTP/2 -的流实现在协议层上,本质上其实只是对引入的更小传输单元帧(Frame)的逻辑承载; + 的流实现在协议层上,本质上其实只是对引入的更小传输单元帧(Frame)的逻辑承载; 2. 理想形态应该是将 HTTP/2 -的实现进行拆分:流(Stream)准备逻辑下层到网络传输层 & 基于流(Stream)的协议处理逻辑保留在协议层。 + 的实现进行拆分:流(Stream)准备逻辑下层到网络传输层 & 基于流(Stream)的协议处理逻辑保留在协议层。 ###### 详细设计 @@ -227,13 +227,13 @@ type Stream interface { type ReceiveStream interface { StreamID() int64 io.Reader - + // CancelRead aborts receiving on this stream. // It will ask the peer to stop transmitting stream data. // Read will unblock immediately, and future Read calls will fail. // When called multiple times or after reading the io.EOF it is a no-op. CancelRead(err ApplicationError) - + // SetReadDeadline sets the deadline for future Read calls and // any currently-blocked Read call. // A zero value for t means Read will not time out. @@ -260,7 +260,7 @@ type SendStream interface { // It must not be called concurrently with Write. // It must not be called after calling CancelWrite. io.Closer - + // The Context is canceled as soon as the write-side of the stream is closed. // This happens when Close() or CancelWrite() is called, or when the peer // cancels the read-side of their stream. @@ -356,7 +356,7 @@ type Core interface {// IsRunning Check whether engine is running or not 1. HTTP/1.1 2. HTTP/2 -排除掉 Netpoll 不支持 TLS 这一点来看,其实网络传输层和协议层是能够自由组合,总共 4(2*2)种不同的搭配。 +排除掉 Netpoll 不支持 TLS 这一点来看,其实网络传输层和协议层是能够自由组合,总共 4(2\*2)种不同的搭配。 但新引入的 StreamConn(网络传输层) 、StreamServer(协议层)其实和上述实现完全平行,如果网络传输层采用 StreamConn 这套抽象接口,协议层也就只能是对接实现了 StreamServer 的 Server 了(目前的 HTTP/1.1、HTTP/2 都不是,不过 HTTP/2 是条流写回对存在改造/重写适配上 StreamConn & StreamServer 的可能性的)。 ## 实现 diff --git a/content/zh/blog/news/Kitex_Dubbo_interoperate/index.md b/content/zh/blog/news/Kitex_Dubbo_interoperate/index.md index 9ee58ca560..b62ce238da 100644 --- a/content/zh/blog/news/Kitex_Dubbo_interoperate/index.md +++ b/content/zh/blog/news/Kitex_Dubbo_interoperate/index.md @@ -50,61 +50,68 @@ Dubbo 主要使用 Hessian2 序列化协议进行 Payload 的编解码,它最 参考 Dubbo 官方的 [dubbo-go-hessian2](https://github.com/apache/dubbo-go-hessian2) 类型映射,codec-dubbo 提供如下类型映射(此处仅包含部分映射,更多注意事项请参考 codec-dubbo Readme ): -| **THRIFT 类型** | **Go 类型** | **HESSIAN2 类型** | **JAVA 类型** | -|:-------------------:|:--------------------:|:-------------------:|:-----------------------:| -| i32 | int32 | int | java.lang.Integer | -| double | float64 | double | java.lang.Double | -| string | string | string | java.lang.String | -| list | \[\]int32 | list | List | -| list | \[\]float64 | list | List | -| list | \[\]string | list | List | -| map | map\[bool\]int32 | map | Map | -| map | map\[bool\]float64 | map | Map | -| map | map\[bool\]string | map | Map | +| **THRIFT 类型** | **Go 类型** | **HESSIAN2 类型** | **JAVA 类型** | +| :---------------: | :----------------: | :---------------: | :-------------------: | +| i32 | int32 | int | java.lang.Integer | +| double | float64 | double | java.lang.Double | +| string | string | string | java.lang.String | +| list | \[\]int32 | list | List | +| list | \[\]float64 | list | List | +| list | \[\]string | list | List | +| map | map\[bool\]int32 | map | Map | +| map | map\[bool\]float64 | map | Map | +| map | map\[bool\]string | map | Map | 根据 codec-dubbo 提供的类型映射,我们能很轻松地将 Dubbo 接口定义转化为 Thrift IDL,并使用 Kitex 命令行工具生成项目脚手架代码,最终注入 DubboCodec 完成 Kitex -> Dubbo 的通信。以下方 Dubbo 接口定义为例: + ```java package org.cloudwego.kitex.samples.api; - + public interface GreetProvider { GreetResponse Greet(GreetRequest req) throws Exception; } - + public class GreetRequest implements Serializable { String req; - + public GreetRequest(String req) { this.req = req; } } - + public class GreetResponse implements Serializable { String resp; - + public GreetResponse(String resp) { this.resp = resp; } } ``` -对应的 api.thrift 文件如下所示,需要注意到其中的结构体定义都需要加上 ```JavaClassName``` 的注解,对应 Dubbo 接口定义中的 package + 类名。 + +对应的 api.thrift 文件如下所示,需要注意到其中的结构体定义都需要加上 `JavaClassName` 的注解,对应 Dubbo 接口定义中的 package + 类名。 + ```thrift struct GreetRequest { 1: required string req, } (JavaClassName="org.cloudwego.kitex.samples.api.GreetRequest") - + struct GreetResponse { 1: required string resp, } (JavaClassName="org.cloudwego.kitex.samples.api.GreetResponse") - + service GreetService { GreetResponse Greet(1: GreetRequest req) } ``` + 使用 Kitex 命令行工具,并指定协议为 Hessian2: + ```shell kitex -module demo-client -protocol Hessian2 ./api.thrift ``` + 之后初始化 DubboCodec 并将其注入 Kitex ,利用生成代码编写以下 Client 端代码即可实现 Kitex -> Dubbo 调用: + ```go javaClass := "org.cloudwego.kitex.samples.api.GreetProvider" cli, err := greetservice.NewClient("helloworld", @@ -119,7 +126,7 @@ cli, err := greetservice.NewClient("helloworld", if err != nil { panic(err) } - + resp, err := cli.Greet(context.Background(), &hello.GreetRequest{Req: "world"}) if err != nil { @@ -128,6 +135,7 @@ if err != nil { } klog.Infof("resp: %s", resp.Resp) ``` + Kitex + codec-dubbo Server 端流程与 Client 端基本类似,具体例子可参考项目主页。 #### 类型拓展 @@ -136,44 +144,49 @@ Hessian2 schema-free 的特性导致 Dubbo 的实现“过于灵活”,可以 ##### 自定义映射 -Java 的基础类型有与之对应的包装类型,例如 ```boolean``` 与 ```java.lang.Boolean```。类型映射中默认将 Go 的 类型映射到 Java 的 ```java.lang.Boolean``` 类型并不能覆盖到使用 ```boolean``` 的情况。 +Java 的基础类型有与之对应的包装类型,例如 `boolean` 与 `java.lang.Boolean`。类型映射中默认将 Go 的 类型映射到 Java 的 `java.lang.Boolean` 类型并不能覆盖到使用 `boolean` 的情况。 + +为了统一用户使用体验,让他们在 Kitex 侧只需使用 `bool` 类型,我们可以在 Thrift 的方法定义后面加上 `hessian.argsType="boolean"` 注解,利用 thriftgo 的 IDL 反射功能,提前生成 IDL 元信息并注入 codec-dubbo,便可以在运行时动态地将默认映射类型 `java.lang.Boolean` 改写成 `boolean` 。具体 Thrift 定义如下所示: -为了统一用户使用体验,让他们在 Kitex 侧只需使用 ```bool``` 类型,我们可以在 Thrift 的方法定义后面加上 ```hessian.argsType="boolean"``` 注解,利用 thriftgo 的 IDL 反射功能,提前生成 IDL 元信息并注入 codec-dubbo,便可以在运行时动态地将默认映射类型 ```java.lang.Boolean``` 改写成 ```boolean``` 。具体 Thrift 定义如下所示: ```thrift service EchoService { bool EchoBoolean(1: bool req) (hessian.argsType="boolean") } ``` -与 ```boolean``` 和 ```java.lang.Boolean``` 类似,其他 Java 基础类型和包装类型也能通过这种方式进行自定义映射,此时 codec-dubbo 提供的完整类型映射如下: - -| **THRIFT 类型** | **GO 类型** | **HESSIAN2 类型** | **默认 JAVA 类型** | **可拓展 JAVA 类型** | -|:-------------------:|:--------------------:|:-------------------:|:-----------------------:|:------------------------------------------:| -| i32 | int32 | int | java.lang.Integer | int | -| double | float64 | double | java.lang.Double | double float / java.lang.Float | -| string | string | string | java.lang.String | \- | -| list | \[\]int32 | list | List | int\[\] / ArrayList | -| list | \[\]float64 | list | List | double\[\] / ArrayList float\[\] | -| list | \[\]string | list | List | String\[\] / ArrayList | -| map | map\[bool\]int32 | map | Map | HashMap | -| map | map\[bool\]float64 | map | Map | HashMap | -| map | map\[bool\]string | map | Map | HashMap | + +与 `boolean` 和 `java.lang.Boolean` 类似,其他 Java 基础类型和包装类型也能通过这种方式进行自定义映射,此时 codec-dubbo 提供的完整类型映射如下: + +| **THRIFT 类型** | **GO 类型** | **HESSIAN2 类型** | **默认 JAVA 类型** | **可拓展 JAVA 类型** | +| :---------------: | :----------------: | :---------------: | :-------------------: | :--------------------------------------: | +| i32 | int32 | int | java.lang.Integer | int | +| double | float64 | double | java.lang.Double | double float / java.lang.Float | +| string | string | string | java.lang.String | \- | +| list | \[\]int32 | list | List | int\[\] / ArrayList | +| list | \[\]float64 | list | List | double\[\] / ArrayList float\[\] | +| list | \[\]string | list | List | String\[\] / ArrayList | +| map | map\[bool\]int32 | map | Map | HashMap | +| map | map\[bool\]float64 | map | Map | HashMap | +| map | map\[bool\]string | map | Map | HashMap | ##### java 常用类型拓展 -由于 Thrift 类型的局限性,我们无法直接使用 Java 类库中提供的常用类型。为此,codec-dubbo 在 [codec-dubbo/java](https://github.com/kitex-contrib/codec-dubbo/tree/main/java) 包中维护了 Thrift 不支持的 Java 类型(例如 ```java.lang.Object``` 、 ```java.util.Date``` )以及与之对应的 [java.thrift](https://github.com/kitex-contrib/codec-dubbo/blob/main/java/java.thrift) ,同时借助 thriftgo 提供的 idl-ref 功能,我们可以直接在 Thrift IDL 中引用这些类型并生成相应代码。当前的 java.thrift 如下所示: +由于 Thrift 类型的局限性,我们无法直接使用 Java 类库中提供的常用类型。为此,codec-dubbo 在 [codec-dubbo/java](https://github.com/kitex-contrib/codec-dubbo/tree/main/java) 包中维护了 Thrift 不支持的 Java 类型(例如 `java.lang.Object` 、 `java.util.Date` )以及与之对应的 [java.thrift](https://github.com/kitex-contrib/codec-dubbo/blob/main/java/java.thrift) ,同时借助 thriftgo 提供的 idl-ref 功能,我们可以直接在 Thrift IDL 中引用这些类型并生成相应代码。当前的 java.thrift 如下所示: + ```thrift struct Object {} (JavaClassName="java.lang.Object") - + struct Date {} (JavaClassName="java.util.Date") - + struct Exception {} (JavaClassName="java.lang.Exception") ``` -为了启用这些类型,我们需要在 Thrift IDL 中使用 ```include "java.thrift"``` 导入它们,并且在使用 Kitex 命令行工具生成代码时添加 ```-hessian2 java_extension``` 参数来拉取该拓展包。 + +为了启用这些类型,我们需要在 Thrift IDL 中使用 `include "java.thrift"` 导入它们,并且在使用 Kitex 命令行工具生成代码时添加 `-hessian2 java_extension` 参数来拉取该拓展包。 Kitex 命令行工具会自动下载 java.thrift ,你也可以手动下载后放到项目的根目录。引用 java.thrift 中类型的 Thrift IDL 示例: + ```thrift include "java.thrift" - + service EchoService { // java.lang.Object i64 EchoString2ObjectMap(1: map req) @@ -181,18 +194,22 @@ service EchoService { i64 EchoDate(1: java.Date req) } ``` + ### 方法重载 -Go 原生不支持方法重载,只能通过定义多个方法来达到类似重载的效果。为了将 Go 中的多个方法映射到 Java 中的重载方法,与自定义映射一节类似,我们在 Thrift 的方法定义后面加上 ```JavaMethodName``` 标签,借助 thriftgo 的 IDL 反射功能在运行时动态地将 Go 侧原本的方法名改写成 ```JavaMethodName``` 指定的 Java 侧中的重载方法。 +Go 原生不支持方法重载,只能通过定义多个方法来达到类似重载的效果。为了将 Go 中的多个方法映射到 Java 中的重载方法,与自定义映射一节类似,我们在 Thrift 的方法定义后面加上 `JavaMethodName` 标签,借助 thriftgo 的 IDL 反射功能在运行时动态地将 Go 侧原本的方法名改写成 `JavaMethodName` 指定的 Java 侧中的重载方法。 以 Java 侧的 EchoMethod 为例: + ```java String EchoMethod(Boolean req); String EchoMethod(Integer req); String EchoMethod(int req); String EchoMethod(Boolean req1, Integer req2); ``` -我们编写如下 Thrift 定义,即可完成 Go 与 Java 间的重载方法映射,注意到 ```JavaMethodName``` 和 ```hessian.argsType``` 可以同时使用: + +我们编写如下 Thrift 定义,即可完成 Go 与 Java 间的重载方法映射,注意到 `JavaMethodName` 和 `hessian.argsType` 可以同时使用: + ```thrift service EchoService { string EchoMethodA(1: bool req) (JavaMethodName="EchoMethod") @@ -201,9 +218,11 @@ service EchoService { string EchoMethodD(1: bool req1, 2: i32 req2) (JavaMethodName="EchoMethod") } ``` + ### 异常处理 codec-dubbo 将 Java 中的异常映射为 Go 中的错误,这些错误统一实现以下接口: + ```go type Throwabler interface { Error() string @@ -211,15 +230,17 @@ type Throwabler interface { GetStackTrace() []StackTraceElement } ``` + 根据 Dubbo 官方推荐的异常处理实践以及企业用户目前的需求,我们将异常划分为常见异常与自定义异常,同时兼顾用户的基础需求以及可扩展需求。 #### 常见异常 -codec-dubbo 在 [pkg/hessian2/exception](https://github.com/kitex-contrib/codec-dubbo/tree/main/pkg/hessian2/exception) 包中提供了 Java 常见的异常,目前支持 ```java.lang.Exception``` 。 +codec-dubbo 在 [pkg/hessian2/exception](https://github.com/kitex-contrib/codec-dubbo/tree/main/pkg/hessian2/exception) 包中提供了 Java 常见的异常,目前支持 `java.lang.Exception` 。 常见异常无需 Kitex 命令行工具的支持,直接引用即可,以下是 Client 端提取异常和 Server 端返回异常的示例。 ##### Client端提取异常 + ```go resp, err := cli.Greet(context.Background(), &hello.GreetRequest{Req: "world"}) @@ -227,35 +248,41 @@ if err != nil { // FromError 返回 Throwabler exceptionRaw, ok := hessian2_exception.FromError(err) if !ok { - // 视作常规错误处理 + // 视作常规错误处理 } else { // 若不关心 exceptionRaw 的具体类型,直接调用 Throwabler 提供的方法即可 - klog.Errorf("get %s type Exception", exceptionRaw.JavaClassName()) + klog.Errorf("get %s type Exception", exceptionRaw.JavaClassName()) // 若想获得 exceptionRaw 的具体类型,需要进行类型转换,但前提是已知该具体类型 exception := exceptionRaw.(*hessian2_exception.Exception) } } ``` + ##### Server端返回异常 + ```go func (s *GreetServiceImpl) Greet(ctx context.Context, req *hello.GreetRequest) (resp *hello.GreetResponse, err error) { return nil, hessian2_exception.NewException("Your detailed message") } ``` + #### 自定义异常 -Java 中的自定义异常往往会继承一个基础异常,这里以 ```CustomizedException``` 为例,```CustomizedException``` 继承了 ```java.lang.Exception``` : +Java 中的自定义异常往往会继承一个基础异常,这里以 `CustomizedException` 为例,`CustomizedException` 继承了 `java.lang.Exception` : + ```java public class CustomizedException extends Exception { private final String customizedMessage; - + public CustomizedException(String customizedMessage) { super(); this.customizedMessage = customizedMessage; } } ``` + 得益于 thriftgo 支持生成嵌套结构体,为了在 Kitex 侧定义与之对应的异常,我们在 Thrift 中编写如下定义: + ```thrift exception CustomizedException { // thrift.nested=“true” 注解让 thriftgo 生成嵌套结构体 @@ -263,16 +290,19 @@ exception CustomizedException { 2: required string customizedMessage }(JavaClassName="org.cloudwego.kitex.samples.api.CustomizedException") ``` -注意 ```exception``` 字段的注解 ```thrift.nested="true"``` ,它让 thriftgo 生成嵌套结构体,达到类似继承的效果。 -和 Java 常用类型扩展一样,需要在使用 kitex 脚手架工具生成代码时添加 ```-hessian2 java_extension``` 参数来拉取拓展包,生成代码如下: +注意 `exception` 字段的注解 `thrift.nested="true"` ,它让 thriftgo 生成嵌套结构体,达到类似继承的效果。 + +和 Java 常用类型扩展一样,需要在使用 kitex 脚手架工具生成代码时添加 `-hessian2 java_extension` 参数来拉取拓展包,生成代码如下: + ```go type EchoCustomizedException struct { java.Exception `thrift:"exception,1,required" frugal:"1,required,java.Exception" json:"exception"` - + CustomizedMessage string `thrift:"customizedMessage,2,required" frugal:"2,required,string" json:"customizedMessage"` } ``` + 使用方法与常见异常一致,此处不再赘述。 ### 服务注册与发现 @@ -285,15 +315,16 @@ Dubbo 同时提供**接口级**与**应用级**服务注册发现模型,根据 综合考虑 Dubbo 接口级服务模型、Kitex API 与用户的使用体验,我们提供以下的配置层次: -1. [registry/options.go](https://github.com/kitex-contrib/codec-dubbo/blob/main/registries/zookeeper/registry/options.go) 与 [resolver/options.go](https://github.com/kitex-contrib/codec-dubbo/blob/main/registries/zookeeper/resolver/options.go) 中的 WithServers 和 WithRegistryGroup 函数提供注册中心级别的配置,分别指定 zookeeper 的地址和这些 zookeeper 所属的组。用户使用这些函数生成 Kitex 中 ```registry.Registry``` 和 ```discovery.Resolver``` 实例。 +1. [registry/options.go](https://github.com/kitex-contrib/codec-dubbo/blob/main/registries/zookeeper/registry/options.go) 与 [resolver/options.go](https://github.com/kitex-contrib/codec-dubbo/blob/main/registries/zookeeper/resolver/options.go) 中的 WithServers 和 WithRegistryGroup 函数提供注册中心级别的配置,分别指定 zookeeper 的地址和这些 zookeeper 所属的组。用户使用这些函数生成 Kitex 中 `registry.Registry` 和 `discovery.Resolver` 实例。 -2. 服务级别的配置由 ```client.WithTag``` 与 ```server.WithRegistryInfo``` 进行传递,[registries/common.go](https://github.com/kitex-contrib/codec-dubbo/blob/main/registries/common.go) 提供 Tag keys ,这些 key 与 Dubbo 中的服务元数据一一对应。 +2. 服务级别的配置由 `client.WithTag` 与 `server.WithRegistryInfo` 进行传递,[registries/common.go](https://github.com/kitex-contrib/codec-dubbo/blob/main/registries/common.go) 提供 Tag keys ,这些 key 与 Dubbo 中的服务元数据一一对应。 #### resolver 示例 + ```go intfName := "org.cloudwego.kitex.samples.api.GreetProvider" res, err := resolver.NewZookeeperResolver( - // 指定 zookeeper 服务器的地址,可指定多个,请至少指定一个 + // 指定 zookeeper 服务器的地址,可指定多个,请至少指定一个 resolver.WithServers("127.0.0.1:2181"), ) if err != nil { @@ -310,17 +341,19 @@ if err != nil { } // 使用 cli 进行 RPC 调用 ``` + #### registry 示例 + ```go intfName := "org.cloudwego.kitex.samples.api.GreetProvider" reg, err := registry.NewZookeeperRegistry( - // 指定 zookeeper 服务器的地址,可指定多个,请至少指定一个 + // 指定 zookeeper 服务器的地址,可指定多个,请至少指定一个 registry.WithServers("127.0.0.1:2181"), ) if err != nil { panic(err) } - + svr := greetservice.NewServer(new(GreetServiceImpl), server.WithRegistry(reg), // 配置dubbo URL元数据 @@ -334,6 +367,7 @@ svr := greetservice.NewServer(new(GreetServiceImpl), ) // 启动 svr ``` + ## 总结 Kitex 支持了 Dubbo 协议,是 CloudWeGo 助力多语言云原生生态融合的一大步,解决了众多企业用户 Java 转 Go 、 Java 与 Go 并存的痛点,欢迎大家试用和接入;如果在使用过程遇到任何问题,可以加入我们的飞书用户群,或者在 Github 上给我们提反馈。 diff --git a/content/zh/blog/news/Kitex_Proxyless_OpenTelemetry/index.md b/content/zh/blog/news/Kitex_Proxyless_OpenTelemetry/index.md index 4bb865d31e..309328a702 100644 --- a/content/zh/blog/news/Kitex_Proxyless_OpenTelemetry/index.md +++ b/content/zh/blog/news/Kitex_Proxyless_OpenTelemetry/index.md @@ -15,10 +15,10 @@ author: CoderPoet ### **Kitex Proxyless** > [Kitex][Kitex] 是字节开源的 Golang RPC 框架,已经原生支持了 xDS 标准协议,支持以 Proxyless 的方式被 ServiceMesh 统一纳管。 -> -> * 详细设计见: +> +> - 详细设计见: > [Proposal: Kitex support xDS Protocol · Issue #461 · cloudwego/kitex](https://github.com/cloudwego/kitex/issues/461) -> * 具体使用方式见[官方文档](/zh/docs/kitex/tutorials/advanced-feature/xds/) +> - 具体使用方式见[官方文档](/zh/docs/kitex/tutorials/advanced-feature/xds/) **[Kitex][Kitex] Proxyless** 简单来说就是 [Kitex][Kitex] 服务能够不借助 envoy sidecar 直接与 istiod 交互,基于 xDS 协议动态获取控制面下发的服务治理规则,并转换为 [Kitex][Kitex] 对应规则来实现一些服务治理功能(例如本文的重点:**流量路由**)。 @@ -43,15 +43,16 @@ author: CoderPoet 3. 感知 RDS 变化,根据 **`VirtualHost`** 和 **`ServiceName`** 来匹配(支持前缀、后缀、精确、通配),获取目标服务的路由配置。 4. 遍历处理匹配到的 RDS 中的路由规则,路由规则主要分为两部分(参考:[路由规范定义](https://github.com/envoyproxy/envoy/blob/v1.13.1/api/envoy/api/v2/route/route_components.proto#L349)): -* **Match** (支持前缀、后缀、精确、通配等),目前版本我们支持以下两种即可: - - * Path(必须项):从 `rpcinfo` 提取 `Method` 进行匹配; - * HeaderMatcher(可选项):从 metainfo 中提取对应元数据 KeyValue,并进行匹配。 -* **Route:** - - * **Cluster** :标准 Cluster。 - * **WeightedClusters(权重路由)** :MW 内根据权重来选择 cluster。 - * 将选择到的 Cluster 写入 `EndpointInfo.Tag`,用于之后的服务发现。 +- **Match** (支持前缀、后缀、精确、通配等),目前版本我们支持以下两种即可: + + - Path(必须项):从 `rpcinfo` 提取 `Method` 进行匹配; + - HeaderMatcher(可选项):从 metainfo 中提取对应元数据 KeyValue,并进行匹配。 + +- **Route:** + + - **Cluster** :标准 Cluster。 + - **WeightedClusters(权重路由)** :MW 内根据权重来选择 cluster。 + - 将选择到的 Cluster 写入 `EndpointInfo.Tag`,用于之后的服务发现。 可以看到,流量路由其实是一个根据一定规则选择对应 SubCluster 的流程。 @@ -82,8 +83,8 @@ author: CoderPoet 通常我们会在网关层进行流量染色,通常会根据原始请求中的元数据,来进行一定规则(条件、比例)转换成对应的染色标识。 -* **按条件染色**:当请求元数据满足一定条件之后,就给当前请求打上染色标识,如:请求头中 `uid = 100`、cookie 匹配等等。 -* **按比例染色**:按照一定比例,给请求打上染色标识。 +- **按条件染色**:当请求元数据满足一定条件之后,就给当前请求打上染色标识,如:请求头中 `uid = 100`、cookie 匹配等等。 +- **按比例染色**:按照一定比例,给请求打上染色标识。 有了一套统一的流量染色机制之后,我们配置路由规则的时候,就不需要关心具体的业务属性标识了,只需要根据**染色标识**来配置即可。 @@ -104,27 +105,27 @@ author: CoderPoet ## 03 案例介绍:Bookinfo > 该案例是使用 [Hertz](https://github.com/cloudwego/hertz)、[Kitex][Kitex] 重写经典的 [Istio Bookinfo](https://istio.io/latest/zh/docs/examples/bookinfo/) 项目: -> -> * 使用 istiod 来作为 **xDS server**,作为 CRD 配置和下发的入口; -> * 使用 wire 来实现**依赖注入**; -> * 使用 opentelemetry 来实现**全链路追踪**; -> * 使用 [Kitex-xds](https://github.com/kitex-contrib/xds) 和 opentelemetry baggage 来实现 **proxyless** 模式下的全链路泳道; -> * 使用 arco-design 和 react 实现一个 **[Bookinfo](https://github.com/cloudwego/biz-demo/blob/main/bookinfo/README_CN.md) UI**。 +> +> - 使用 istiod 来作为 **xDS server**,作为 CRD 配置和下发的入口; +> - 使用 wire 来实现**依赖注入**; +> - 使用 opentelemetry 来实现**全链路追踪**; +> - 使用 [Kitex-xds](https://github.com/kitex-contrib/xds) 和 opentelemetry baggage 来实现 **proxyless** 模式下的全链路泳道; +> - 使用 arco-design 和 react 实现一个 **[Bookinfo](https://github.com/cloudwego/biz-demo/blob/main/bookinfo/README_CN.md) UI**。 ### 架构 整体架构与 [Bookinfo](https://github.com/cloudwego/biz-demo/blob/main/bookinfo/README_CN.md) 保持一致,分为四个单独的微服务: -* `productpage.` 这个微服务会调 `details` 和 `reviews` 两个微服务; -* `details.` 这个微服务中包含了书籍的信息; -* `reviews.` 这个微服务中包含了书籍相关的评论。它还会调用 `ratings` 微服务; -* `ratings.` 这个微服务中包含了由书籍评价组成的评级信息。 +- `productpage.` 这个微服务会调 `details` 和 `reviews` 两个微服务; +- `details.` 这个微服务中包含了书籍的信息; +- `reviews.` 这个微服务中包含了书籍相关的评论。它还会调用 `ratings` 微服务; +- `ratings.` 这个微服务中包含了由书籍评价组成的评级信息。 `reviews` 微服务有 3 个版本: -* v1 版本会调用 `ratings` 服务,并使用 1 颗 ⭐️ 显示评分; -* v2 版本会调用 `ratings` 服务,并使用 5 颗 ⭐️⭐️⭐️⭐️⭐️⭐️ 显示评分; -* v3 版本不会调用 `ratings` 服务。 +- v1 版本会调用 `ratings` 服务,并使用 1 颗 ⭐️ 显示评分; +- v2 版本会调用 `ratings` 服务,并使用 5 颗 ⭐️⭐️⭐️⭐️⭐️⭐️ 显示评分; +- v3 版本不会调用 `ratings` 服务。 ![image](/img/blog/Kitex_Proxyless/5.png) @@ -132,8 +133,8 @@ author: CoderPoet 整体区分成 2 个泳道: -* **基准泳道**:未被染色的流量会被路由到基准泳道中。 -* **分支泳道**:被染色的流量会被路由到 reviews-v2 ->ratings-v2 的分支泳道中。 +- **基准泳道**:未被染色的流量会被路由到基准泳道中。 +- **分支泳道**:被染色的流量会被路由到 reviews-v2 ->ratings-v2 的分支泳道中。 ![image](/img/blog/Kitex_Proxyless/6.png) @@ -155,9 +156,9 @@ author: CoderPoet 2. 基于 **DestinationRule** 为服务设置一系列的 subsets: -> * Productpage: v1 -> * Reviews: v1、v2、v3 -> * Ratings: v1、v2 +> - Productpage: v1 +> - Reviews: v1、v2、v3 +> - Ratings: v1、v2 ![image](/img/blog/Kitex_Proxyless/9.png) @@ -187,7 +188,7 @@ author: CoderPoet ## 04 总结与展望 -至此我们已经基于 **[Kitex][Kitex] Proxyless** 与 **OpenTelemetry** 实现了一个完整的全链路泳道,并且无需借助 Envoy sidecar,就能基于 Isito 标准治理规则 Spec,来为 Kitex 设置对应的路由规则了。 +至此我们已经基于 **[Kitex][Kitex] Proxyless** 与 **OpenTelemetry** 实现了一个完整的全链路泳道,并且无需借助 Envoy sidecar,就能基于 Isito 标准治理规则 Spec,来为 Kitex 设置对应的路由规则了。 当然,除了满足**流量路由**能力之外,**[Kitex][Kitex] Proxyless** 也在持续迭代优化,满足更多数据面治理能力需求。Proxyless 作为一种 ServiceMesh 数据面探索和实践,除了能够丰富网格数据面部署形态之外,也希望可以不断打磨 **[Kitex][Kitex]**,增强其在开源生态兼容方面的能力,打造一个开放包容的微服务生态体系。 @@ -195,12 +196,12 @@ author: CoderPoet 下面是该案例涉及的项目清单: -* biz-demo: https://github.com/cloudwego/biz-demo -* kitex: https://github.com/cloudwego/kitex -* hertz: https://github.com/cloudwego/hertz -* kitex-xds: https://github.com/kitex-contrib/xds -* kitex-opentelemetry: https://github.com/kitex-contrib/obs-opentelemetry -* hertz-opentelemetry: https://github.com/hertz-contrib/obs-opentelemetry +- biz-demo: https://github.com/cloudwego/biz-demo +- kitex: https://github.com/cloudwego/kitex +- hertz: https://github.com/cloudwego/hertz +- kitex-xds: https://github.com/kitex-contrib/xds +- kitex-opentelemetry: https://github.com/kitex-contrib/obs-opentelemetry +- hertz-opentelemetry: https://github.com/hertz-contrib/obs-opentelemetry 该完整案例已提交在 [biz-demo][biz-demo] 仓库中,感兴趣的同学可以前往查阅。[biz-demo][biz-demo] 会包含一些基于 [CloudWeGo](https://github.com/cloudwego) 技术栈且具备一定业务场景的完整 Demo,初衷是能够为企业用户在生产中使用提供有价值的参考,非常欢迎更多同学能够参与到 [CloudWeGo](https://github.com/cloudwego) 相关场景与案例的贡献中来,一起来做一些有意思的尝试。 diff --git a/content/zh/blog/news/Kitex_perf_optimize_practices/index.md b/content/zh/blog/news/Kitex_perf_optimize_practices/index.md index c48c495412..dc462eafdc 100644 --- a/content/zh/blog/news/Kitex_perf_optimize_practices/index.md +++ b/content/zh/blog/news/Kitex_perf_optimize_practices/index.md @@ -58,12 +58,11 @@ send_events: Benchmark 表明,在有事件触发的情况下,msec=0 比 msec=-1 调用要快 18% 左右,因此在频繁事件触发场景下,使用 msec=0 调用明显是更优的。 -|Benchmark|time/op|bytes/op| -|:----|:----|:----| -|BenchmarkEpollWait, msec=0|270 ns/op|0 B/op| -|BenchmarkEpollWait, msec=-1|328 ns/op|0 B/op| -|EpollWait Delta|-17.68%|~| - +| Benchmark | time/op | bytes/op | +| :-------------------------- | :-------- | :------- | +| BenchmarkEpollWait, msec=0 | 270 ns/op | 0 B/op | +| BenchmarkEpollWait, msec=-1 | 328 ns/op | 0 B/op | +| EpollWait Delta | -17.68% | ~ | 而在无事件触发的场景下,使用 msec=0 显然会造成无限轮询,空耗大量资源。 @@ -215,17 +214,17 @@ func StringToSliceByte(s string) []byte { - 基本类型 - - 如果容器元素为基本类型(bool, byte, i16, i32, i64, double)的话,由于基本类型大小固定,在序列化时是可以提前计算出总的大小,并且一次性分配足够的 buffer,O(n) 的 malloc 操作次数可以降到 O(1),从而大量减少了 malloc 的次数,同理在反序列化时可以减少 next 的操作次数。 + - 如果容器元素为基本类型(bool, byte, i16, i32, i64, double)的话,由于基本类型大小固定,在序列化时是可以提前计算出总的大小,并且一次性分配足够的 buffer,O(n) 的 malloc 操作次数可以降到 O(1),从而大量减少了 malloc 的次数,同理在反序列化时可以减少 next 的操作次数。 - struct 字段重排 - - 上面的优化只能针对容器元素类型为基本类型的有效,那么对于元素类型为 struct 的是否也能优化呢?答案是肯定的。 + - 上面的优化只能针对容器元素类型为基本类型的有效,那么对于元素类型为 struct 的是否也能优化呢?答案是肯定的。 - - 沿用上面的思路,假如 struct 中如果存在基本类型的 field,也可以预先计算出这些 field 的大小,在序列化时为这些 field 提前分配 buffer,写的时候也把这些 field 顺序统一放到前面写,这样也能在一定程度上减少 malloc 的次数。 + - 沿用上面的思路,假如 struct 中如果存在基本类型的 field,也可以预先计算出这些 field 的大小,在序列化时为这些 field 提前分配 buffer,写的时候也把这些 field 顺序统一放到前面写,这样也能在一定程度上减少 malloc 的次数。 - 一次性计算 - - 上面提到的是基本类型的优化,如果在序列化时,先遍历一遍 request 所有 field,便可以计算得到整个 request 的大小,提前分配好 buffer,在序列化和反序列时直接操作 buffer,这样对于非基本类型也能有优化效果。 + - 上面提到的是基本类型的优化,如果在序列化时,先遍历一遍 request 所有 field,便可以计算得到整个 request 的大小,提前分配好 buffer,在序列化和反序列时直接操作 buffer,这样对于非基本类型也能有优化效果。 - 定义新的 codec 接口: @@ -356,11 +355,10 @@ go test -gcflags='-m=2 -l=4' -v -test.run TestNewCodec 2>&1 | grep "function too 从上面的输出结果可以看出,加强内联程度确实减少了一些"function too complex",看下 benchmark 结果: -|Benchmark|time/op|bytes/op|allocs/op| -|:----|:----|:----|:----| -|BenchmarkOldMarshal-4|309 µs ± 2%|218KB|11| -|BenchmarkNewMarshal-4|310 µs ± 3%|218KB|11| - +| Benchmark | time/op | bytes/op | allocs/op | +| :-------------------- | :---------- | :------- | :-------- | +| BenchmarkOldMarshal-4 | 309 µs ± 2% | 218KB | 11 | +| BenchmarkNewMarshal-4 | 310 µs ± 3% | 218KB | 11 | 上面开启最高程度的内联强度,确实消除了不少因为“function too complex”带来无法内联的函数,但是压测结果显示收益不太明显。 @@ -374,27 +372,27 @@ go test -gcflags='-m=2 -l=4' -v -test.run TestNewCodec 2>&1 | grep "function too data size: 20KB -|Benchmark|time/op|bytes/op|allocs/op| -|:----|:----|:----|:----| -|BenchmarkOldMarshal-4|138 µs ± 3%|25.4KB|19| -|BenchmarkNewMarshal-4|29 µs ± 3%|26.4KB|11| -|Marshal Delta|-78.97%|3.87%|-42.11%| -|BenchmarkOldUnmarshal-4|199 µs ± 3%|4720|1360| -|BenchmarkNewUnmarshal-4|94µs ± 5%|4700|1280| -|Unmarshal Delta|-52.93%|-0.24%|-5.38%| +| Benchmark | time/op | bytes/op | allocs/op | +| :---------------------- | :---------- | :------- | :-------- | +| BenchmarkOldMarshal-4 | 138 µs ± 3% | 25.4KB | 19 | +| BenchmarkNewMarshal-4 | 29 µs ± 3% | 26.4KB | 11 | +| Marshal Delta | -78.97% | 3.87% | -42.11% | +| BenchmarkOldUnmarshal-4 | 199 µs ± 3% | 4720 | 1360 | +| BenchmarkNewUnmarshal-4 | 94µs ± 5% | 4700 | 1280 | +| Unmarshal Delta | -52.93% | -0.24% | -5.38% | **大包** data size: 6MB -|Benchmark|time/op|bytes/op|allocs/op| -|:----|:----|:----|:----| -|BenchmarkOldMarshal-4|58.7ms ± 5%|6.96MB|3350| -|BenchmarkNewMarshal-4|13.3ms ± 3%|6.84MB|10| -|Marshal Delta|-77.30%|-1.71%|-99.64%| -|BenchmarkOldUnmarshal-4|56.6ms ± 3%|17.4MB|391000| -|BenchmarkNewUnmarshal-4|26.8ms ± 5%|17.5MB|390000| -|Unmarshal Delta|-52.54%|0.09%|-0.37%| +| Benchmark | time/op | bytes/op | allocs/op | +| :---------------------- | :---------- | :------- | :-------- | +| BenchmarkOldMarshal-4 | 58.7ms ± 5% | 6.96MB | 3350 | +| BenchmarkNewMarshal-4 | 13.3ms ± 3% | 6.84MB | 10 | +| Marshal Delta | -77.30% | -1.71% | -99.64% | +| BenchmarkOldUnmarshal-4 | 56.6ms ± 3% | 17.4MB | 391000 | +| BenchmarkNewUnmarshal-4 | 26.8ms ± 5% | 17.5MB | 390000 | +| Unmarshal Delta | -52.54% | 0.09% | -0.37% | ## 无拷贝序列化 @@ -419,8 +417,8 @@ Cap'n Proto 本质上是开辟一个 bytes slice 作为 buffer ,所有对数 - 在数据交换格式中,通过 pointer(数据存储位置的 offset)机制,使得数据可以存储在连续内存的任意位置,进而使得结构体中的数据可以以任意顺序读写 - - 对于结构体的固定大小字段,通过重新排列,使得这些字段存储在一块连续内存中 - - 对于结构体的不定大小字段(如 list),则通过一个固定大小的 pointer 来表示,pointer 中存储了包括数据位置在内的一些信息 + - 对于结构体的固定大小字段,通过重新排列,使得这些字段存储在一块连续内存中 + - 对于结构体的不定大小字段(如 list),则通过一个固定大小的 pointer 来表示,pointer 中存储了包括数据位置在内的一些信息 首先 Cap'n Proto 没有 Go 语言结构体作为中间载体,得以减少一次拷贝,然后 Cap'n Proto 是在一段连续内存上进行操作,编码数据的读写可以一次完成,因为这两个原因,使得 Cap' Proto 的性能表现优秀。 @@ -438,11 +436,11 @@ struct Ano { } ``` -|Benchmark|Iter|time/op|bytes/op|alloc/op| -|:----|:----|:----|:----|:----| -|BenchmarkThriftReadWrite|172|6855840 ns/op|3154209 B/op|545 allocs/op| -|BenchmarkCapnpReadWrite|1500|844924 ns/op|2085713 B/op|9 allocs/op| -|ReadWrite Delta|/|-87.68%|-33.88%|-98.35%| +| Benchmark | Iter | time/op | bytes/op | alloc/op | +| :----------------------- | :--- | :------------ | :----------- | :------------ | +| BenchmarkThriftReadWrite | 172 | 6855840 ns/op | 3154209 B/op | 545 allocs/op | +| BenchmarkCapnpReadWrite | 1500 | 844924 ns/op | 2085713 B/op | 9 allocs/op | +| ReadWrite Delta | / | -87.68% | -33.88% | -98.35% | (反序列化)+读出数据,视包大小,Cap'n Proto 性能大约是 Thrift 的 8-9 倍。写入数据+(序列化),视包大小,Cap'n Proto 性能大约是 Thrift 的 2-8 倍。整体性能 Cap' Proto 性能大约是 Thrift 的 4-8 倍。 @@ -464,10 +462,10 @@ Cap'n Proto 作为无拷贝序列化的标杆,那么我们就看看 Cap'n Prot - Cap'n Proto 是在一段连续内存上进行操作,编码数据的读写可以一次完成。Cap'n Proto 得以在连续内存上操作的原因:有 pointer 机制,数据可以存储在任意位置,允许字段可以以任意顺序写入而不影响解码。 但是一方面,在连续内存上容易因为误操作,导致在 resize 的时候留下 hole,另一方面,Thrift 没有类似于 pointer 的机制,故而对数据布局有着更严格的要求。这里有两个思路: - - 坚持在连续内存上进行操作,并对用户使用提出严格要求:1. resize 操作必须重新构建数据结构 2. 当存在结构体嵌套时,对字段写入顺序有着严格要求(可以想象为把一个存在嵌套的结构体从外往里展开,写入时需要按展开顺序写入), - 且因为 Binary 等 TLV 编码的关系,在每个嵌套开始写入时,需要用户主动声明(如 StartWriteFieldX)。 - - 不完全在连续内存上操作,局部内存连续,可变字段则单独分配一块内存,既然内存不是完全连续的,自然也无法做到一次写操作便完成输出。为了尽可能接近一次写完数据的性能,我们采取了一种链式 buffer 的方案, - 一方面当可变字段 resize 时只需替换链式 buffer 的一个节点,无需像 Cap'n Proto 一样重新构建结构体,另一方面在需要输出时无需像 Thrift 一样需要感知实际的结构,只要把整个链路上的 buffer 写入即可。 + - 坚持在连续内存上进行操作,并对用户使用提出严格要求:1. resize 操作必须重新构建数据结构 2. 当存在结构体嵌套时,对字段写入顺序有着严格要求(可以想象为把一个存在嵌套的结构体从外往里展开,写入时需要按展开顺序写入), + 且因为 Binary 等 TLV 编码的关系,在每个嵌套开始写入时,需要用户主动声明(如 StartWriteFieldX)。 + - 不完全在连续内存上操作,局部内存连续,可变字段则单独分配一块内存,既然内存不是完全连续的,自然也无法做到一次写操作便完成输出。为了尽可能接近一次写完数据的性能,我们采取了一种链式 buffer 的方案, + 一方面当可变字段 resize 时只需替换链式 buffer 的一个节点,无需像 Cap'n Proto 一样重新构建结构体,另一方面在需要输出时无需像 Thrift 一样需要感知实际的结构,只要把整个链路上的 buffer 写入即可。 先总结下目前确定的两个点:1. 不使用 Go 语言结构体作为中间载体,通过接口直接操作底层内存,在 Get/Set 时完成编解码 2. 通过链式 buffer 存储数据 @@ -475,29 +473,28 @@ Cap'n Proto 作为无拷贝序列化的标杆,那么我们就看看 Cap'n Prot - 不使用 Go 语言结构体后带来的用户体验劣化 - - 解决方案:改善 Get/Set 接口的使用体验,尽可能做到和 Go 语言结构体同等的易用 + - 解决方案:改善 Get/Set 接口的使用体验,尽可能做到和 Go 语言结构体同等的易用 - Cap'n Proto 的 Binary Format 是针对无拷贝序列化场景专门设计的,虽然每次 Get 时都会进行一次解码,但是解码代价非常小。而 Thrift 的协议(以 Binary 为例),没有类似于 pointer 的机制, 当存在多个不定大小字段或者存在嵌套时,必须顺序解析而无法直接通过计算偏移拿到字段数据所在的位置,而每次 Get 都进行顺序解析的代价过于高昂。 - - 解决方案:我们在表示结构体的时候,除了记录结构体的 buffer 节点,还加了一个索引,里面记录了每个不定大小字段开始的 buffer 节点的指针。 - 下面是目前的无拷贝序列化方案与 FastRead/Write,在 4 核下的极限性能对比测试: - -|包大小|类型|QPS|TP90|TP99|TP999|CPU| -|:----|:----|:----|:----|:----|:----|:----| -|1KB|无序列化|70,700|1 ms|3 ms|6 ms|/| -| |FastWrite/FastRead|82,490|1 ms|2 ms|4 ms|/| -|2KB|无序列化|65,000|1 ms|4 ms|9 ms|/| -| |FastWrite/FastRead|72,000|1 ms|2 ms|8 ms|/| -|4KB|无序列化|56,400|2 ms|5 ms|10 ms|380%| -| |FastWrite/FastRead|52,700|2 ms|4 ms|10 ms|380%| -|32KB|无序列化|27,400|/|/|/|/| -| |FastWrite/FastRead|19,500|/|/|/|/| -|1MB|无序列化|986|53 ms|56 ms|59 ms|260%| -| |FastWrite/FastRead|942|55 ms|59 ms|62 ms|290%| -|10MB|无序列化|82|630 ms|640 ms|645 ms|240%| -| |FastWrite/FastRead|82|630 ms|640 ms|640 ms|270%| - + - 解决方案:我们在表示结构体的时候,除了记录结构体的 buffer 节点,还加了一个索引,里面记录了每个不定大小字段开始的 buffer 节点的指针。 + 下面是目前的无拷贝序列化方案与 FastRead/Write,在 4 核下的极限性能对比测试: + +| 包大小 | 类型 | QPS | TP90 | TP99 | TP999 | CPU | +| :----- | :----------------- | :----- | :----- | :----- | :----- | :--- | +| 1KB | 无序列化 | 70,700 | 1 ms | 3 ms | 6 ms | / | +| | FastWrite/FastRead | 82,490 | 1 ms | 2 ms | 4 ms | / | +| 2KB | 无序列化 | 65,000 | 1 ms | 4 ms | 9 ms | / | +| | FastWrite/FastRead | 72,000 | 1 ms | 2 ms | 8 ms | / | +| 4KB | 无序列化 | 56,400 | 2 ms | 5 ms | 10 ms | 380% | +| | FastWrite/FastRead | 52,700 | 2 ms | 4 ms | 10 ms | 380% | +| 32KB | 无序列化 | 27,400 | / | / | / | / | +| | FastWrite/FastRead | 19,500 | / | / | / | / | +| 1MB | 无序列化 | 986 | 53 ms | 56 ms | 59 ms | 260% | +| | FastWrite/FastRead | 942 | 55 ms | 59 ms | 62 ms | 290% | +| 10MB | 无序列化 | 82 | 630 ms | 640 ms | 645 ms | 240% | +| | FastWrite/FastRead | 82 | 630 ms | 640 ms | 640 ms | 270% | 测试结果概述: diff --git a/content/zh/blog/news/Kitex_performance_testing/index.md b/content/zh/blog/news/Kitex_performance_testing/index.md index 82d81e574f..751cf2662c 100644 --- a/content/zh/blog/news/Kitex_performance_testing/index.md +++ b/content/zh/blog/news/Kitex_performance_testing/index.md @@ -16,17 +16,17 @@ author: Joway [Kitex][Kitex] 诞生于字节跳动大规模微服务架构实践,面向的场景自然是微服务场景,因此下面会先介绍微服务的特点,方便开发者深入理解 [Kitex][Kitex] 在其中的设计思考。 -* RPC 通信模型 +- RPC 通信模型 微服务间的通信通常以 PingPong 模型为主,所以除了常规的吞吐性能指标外,每次 RPC 的平均时延也是开发者需要考虑的点。 -* 复杂的调用链路 +- 复杂的调用链路 一次 RPC 调用往往需要多个微服务协作完成,而下游服务又会有其自身依赖,所以整个调用链路会是一个复杂的网状结构。 在这种复杂调用关系中,某个中间节点出现的延迟波动可能会传导到整个链路上,导致整体超时。当链路上的节点足够多时,即便每个节点的波动概率很低,最终汇聚到链路上的超时概率也会被放大。 所以单一服务的延迟波动 —— 即 P99 延迟指标,也是一个会对线上服务产生重大影响的关键指标。 -* 包体积大小 +- 包体积大小 虽然一个服务通信包的大小取决于实际业务场景,但在字节跳动的内部统计中,我们发现线上请求大多以小包(<2KB)为主,所以在兼顾大包场景的同时,也重点优化了小包场景下的性能。 @@ -43,9 +43,10 @@ author: Joway ### 对齐连接模型 常规 RPC 的连接模型主要有三种: -* **短连接**:每次请求都创建新连接,得到返回后立即关闭连接 -* **长连接池**:单个连接同时只能处理一次完整请求与返回 -* **连接多路复用**:单个连接可以同时异步处理多个请求与返回 + +- **短连接**:每次请求都创建新连接,得到返回后立即关闭连接 +- **长连接池**:单个连接同时只能处理一次完整请求与返回 +- **连接多路复用**:单个连接可以同时异步处理多个请求与返回 每类连接模型没有绝对好坏,取决于实际使用场景。连接多路复用虽然一般来说性能相对最好,但应用上必须依赖协议能够支持包序列号,且一些老框架服务可能也并不支持多路复用的方式调用。 @@ -75,14 +76,14 @@ author: Joway **配置:** -* Client 16 CPUs,Server 4 CPUs -* 1KB 请求大小,Echo 场景 +- Client 16 CPUs,Server 4 CPUs +- 1KB 请求大小,Echo 场景 **参考数据:** -* KITEX:连接池模式(默认模式) -* KITEX-MUX:多路复用模式 -* 其他框架均使用多路复用模式 +- KITEX:连接池模式(默认模式) +- KITEX-MUX:多路复用模式 +- 其他框架均使用多路复用模式 ![image](/img/blog/kitex_performance_testing/qps.png) ![image](/img/blog/kitex_performance_testing/tp99.png) @@ -97,16 +98,16 @@ author: Joway ## 相关链接 -* Kitex: https://github.com/cloudwego/kitex +- Kitex: https://github.com/cloudwego/kitex -* Netpoll: https://github.com/cloudwego/netpoll +- Netpoll: https://github.com/cloudwego/netpoll -* kitex-benchmark: https://github.com/cloudwego/kitex-benchmark +- kitex-benchmark: https://github.com/cloudwego/kitex-benchmark -* netpoll-benchmark: https://github.com/cloudwego/netpoll-benchmark +- netpoll-benchmark: https://github.com/cloudwego/netpoll-benchmark -* 官方 Protobuf 库: https://github.com/golang/protobuf +- 官方 Protobuf 库: https://github.com/golang/protobuf -* Thriftgo: https://github.com/cloudwego/thriftgo +- Thriftgo: https://github.com/cloudwego/thriftgo [Kitex]: https://github.com/cloudwego/kitex diff --git a/content/zh/blog/news/Rust_or_Go/index.md b/content/zh/blog/news/Rust_or_Go/index.md index 66fb003dab..effd096ee7 100644 --- a/content/zh/blog/news/Rust_or_Go/index.md +++ b/content/zh/blog/news/Rust_or_Go/index.md @@ -14,17 +14,17 @@ CloudWeGo 正式官宣新一代 Rust RPC 框架 [Volo][Volo] 开源!CloudWeGo ### Go 的代价 -* **深度优化困难** +- **深度优化困难** [Volo][Volo] 早期的团队成员来自于 [Kitex][Kitex] 项目(CloudWeGo 开源的 Golang 微服务 RPC 框架)。当时我们投入了大量的时间和精力优化 [Kitex][Kitex] 以及其他相关基础库的性能,最终却发现实现 Go 的深度优化有些困难。 我们仅仅可以做一些算法层面和实现层面的优化,如果想往下继续做其他层面的优化,比如指令层面的优化,是很难以低成本的方式实现的。而且在大多数情况下很多优化是要和 runtime 以及编译器作斗争的。 -* **工具链和包管理不够成熟** +- **工具链和包管理不够成熟** 例如,使用 [Kitex][Kitex] 框架时需要先使用对应的 kitex 工具生成代码,才能正常编译使用。虽然这种情况可能在 [Frugal][Frugal] 工具成熟之后有所改善,但是在 IDL 有更新的情况下,还是需要使用 kitex 重新生成对应的结构体。 这个问题并不是 [Kitex][Kitex] 的问题,而是 Go 语言本身的问题,Go 语言在编译时没有提供类似的能力。 -* **抽象能力较弱** +- **抽象能力较弱** Go 语言的抽象能力是比较弱的,而且 Go 语言里面的抽象并不是零成本抽象,而是有代价的抽象。 @@ -51,7 +51,7 @@ Kitex 旧版本的代码 ![image](/img/blog/Rust_or_Go/4.png) -那么这会带来什么问题呢?由于我们主流程中的代码与正常流程相比变多了,所以我们重点关注一下 `L1-icache-load-misses` 这一行, +那么这会带来什么问题呢?由于我们主流程中的代码与正常流程相比变多了,所以我们重点关注一下 `L1-icache-load-misses` 这一行, 新版本的代码比旧版本的代码在 L1 指令 `cache` 层面 `cache-misses` 高出 20%,这也就是我们的代码效率降低 20% 的原因。那么我们是如何解决这个问题的呢? 我们的解决方案如下图所示。在 `err != nil` 的情况下,直接手动加一条 `goto` 语句,把所有错误处理这部分的代码放到函数末尾,即 `return` 之后。 @@ -66,8 +66,8 @@ Kitex 旧版本的代码 什么是零成本抽象呢?使用 C++ 和 Rust 的同学对这个概念可能有所了解。零成本抽象是指我们不需要对没有使用的功能付出编译和运行的开销,也就是用户不需要给没有使用的东西付费。 对应地,如果用户对于已经使用的东西也没有再继续优化的空间,因为它已经默认提供了最佳实践。总结如下: -* 不用的东西,不需要为之付出代价; -* 用到的东西,你也不可能做得更好。 +- 不用的东西,不需要为之付出代价; +- 用到的东西,你也不可能做得更好。 那么为什么说 Go 语言里面没有零成本抽象呢?以 Thrift 编解码为例,我们最开始使用的是 Apache Thrift,它为了支持多种不同 Protocol、Transport 组合, 抽象出了 TProtocol Interface、TTransport Interface,但 [Kitex][Kitex] 直接依赖具体的 BinaryProtocol 的实现(struct)。可以试想,Apache Thrift 这么做的代价是什么呢?这就是 Go 里面 Interface 带来的代价。 @@ -120,7 +120,7 @@ Rust 最关注也是大家经常诟病的一点,就是 Rust 的整个学习曲 在 2022 年,很多开源项目已经呈现爆炸式增长。我们了解到 Rust 这门语言后,发现它有三大非常重要的优势:第一是高性能;第二是很强的安全性;第三是协作方便。 因此我们想尝试在服务端使用 Rust 语言开发微服务,以此解决我们面临的一些性能上的问题。 -* **性能** +- **性能** 很多用户都对性能有很高的要求,也想知道 Rust 的性能如何。下图是各语言的 Benchmark 对比结果,可以看出 Rust 的性能是非常优秀的,远超过 Go 语言,甚至比 C++ 的性能更好。 @@ -129,13 +129,13 @@ Rust 最关注也是大家经常诟病的一点,就是 Rust 的整个学习曲 ![image](/img/blog/Rust_or_Go/11.png) -* **安全性** +- **安全性** 因为在 Rust 语言的安全性方面可查阅到大量资料,因此不再过多赘述。只阐述一个重要结论:Rust 1.0 之后,在非 Unsafe 代码中是不可能出现内存安全问题的。 这个结论是通过数学证明过的,因此非常可靠。我们应该如何理解这个结论呢?可以从它的推论入手,即:一切内存/并发安全问题,都是 unsafe 代码导致的。 也就是如果真的出现安全问题,我们可以限制在一个非常小的范围内进行排查。因为毕竟绝大多数的 Rust 语言代码都是 Safe Rust,而不是 Unsafe Rust。 -* **协作** +- **协作** Rust 是一门真正通过工程实践形成的语言,它有非常 **智能的编译器** 、 **完善的文档** 、**集群的工具链**和 **成熟的包管理** ,因此 Rust 非常适合协作。 我们在使用时可以专注于逻辑功能的实现,而不用担心内存安全和并发安全的问题等等。还有非常重要的一点就是可以限制别人的代码,因为如果别人的代码有内存安全问题或并发安全问题,将无法进行编译。 @@ -171,18 +171,18 @@ Rust 以难学难用而闻名,我们希望尽可能地降低用户使用 [Volo ![image](/img/blog/Rust_or_Go/14.png) -除此之外,我们提供了 [Volo][Volo] **命令行工具生成默认 Layout** ,并且 [Volo][Volo] 的命令行工具提供 **IDL 管理的能力** ,这在业界是首例。 +除此之外,我们提供了 [Volo][Volo] **命令行工具生成默认 Layout** ,并且 [Volo][Volo] 的命令行工具提供 **IDL 管理的能力** ,这在业界是首例。 我们还提供了过程宏等能够再度降低 Service 编写难度的功能。当然还有很多其他的精心设计,比如很多 API 都是尽量以最符合人体工程学的方式给出的,也可以避免误用。 ### 扩展性 -* **基于 Service 的抽象** +- **基于 Service 的抽象** -受益于 Rust 强大的表达和抽象能力,开发者可以基于非常灵活的 Service 抽象,用统一的形式对 RPC 的元信息请求和响应做一些处理,比如服务发现、负载均衡等服务治理功能都是直接实现 Service 即可。 +受益于 Rust 强大的表达和抽象能力,开发者可以基于非常灵活的 Service 抽象,用统一的形式对 RPC 的元信息请求和响应做一些处理,比如服务发现、负载均衡等服务治理功能都是直接实现 Service 即可。 ![image](/img/blog/Rust_or_Go/15.png) -* **基于 RPC 元信息的控制** +- **基于 RPC 元信息的控制** 另外,在我们的框架设计中,所有框架行为都是受到 RPC 元信息控制的。因此我们只要在 Service 中对 RPC 元信息进行修改,就能直接控制框架的行为,从而实现所需的功能。 @@ -195,16 +195,16 @@ Rust 以难学难用而闻名,我们希望尽可能地降低用户使用 [Volo 如果过多谈论框架的性能对比,容易引战。但是基于 Rust 语言的性能优势以及 CloudWeGo 团队对于极致性能的追求,我们可以预想到 [Volo][Volo] 的性能也是非常高的。 如果把 [Volo][Volo] 和 [Kitex][Kitex] 进行跨语言的对比也是不太公平的,但是因为很多用户都关注性能数据,为了让使用者对 [Volo][Volo] 框架的性能有大致的了解,我们只给出比较简单的性能数据。 -在与 [Kitex][Kitex] 相同的测试条件(限制 4C)下,[Volo][Volo] 极限 QPS 为 35W。同时,我们内部正在验证基于 [Monoio][Monoio](CloudWeGo 开源的 Rust Async Runtime)的版本,极限 QPS 可以达到 44W。 +在与 [Kitex][Kitex] 相同的测试条件(限制 4C)下,[Volo][Volo] 极限 QPS 为 35W。同时,我们内部正在验证基于 [Monoio][Monoio](CloudWeGo 开源的 Rust Async Runtime)的版本,极限 QPS 可以达到 44W。 当然还有很多其他的性能指标,比如响应时间也是非常影响用户体验的。所以除了 Benchmark,我们选取了由 Go 迁移到 [Volo][Volo] 框架的两个业务,呈现真实的业务落地收益。 1. **业务 A(Proxy 类)** 。A 业务的 IO 比较多,迁移到 [Volo][Volo] 框架后的各方面数据如下: -* CPU Usage 630% -> 380% -* MEM 9GB -> 2GB -* P99 150-200ms -> 20-35ms -* AVG 4-5ms -> 1.5ms +- CPU Usage 630% -> 380% +- MEM 9GB -> 2GB +- P99 150-200ms -> 20-35ms +- AVG 4-5ms -> 1.5ms 可以看出不论是 CPU、内存还是延时的指标,都有非常明显的提升。下图中间红线代表 [Volo][Volo] 上线的时间,也就是红线左侧这一部分是 Go 的指标,红线右侧是 Rust 的指标,左右对比可以更直观看出 [Volo][Volo] 框架给业务 A 带来的收益。 @@ -216,11 +216,11 @@ Rust 以难学难用而闻名,我们希望尽可能地降低用户使用 [Volo 随着 [Volo][Volo] 框架开源,一起开源的所有生态如下: -* **Volo** 是 RPC 框架的名字,包含了 Volo-Thrift 和 Volo-gRPC 两部分。 -* **Volo-rs 组织** :Volo 的相关生态。 -* **Pilota** :Volo 使用的 Thrift 与 Protobuf 编译器及编解码的纯 Rust 实现(不依赖 protoc)。 -* **Motore** :Volo 参考 Tower 设计的,使用了 GAT 和 TAIT 的 middleware 抽象层。 -* **Metainfo** :Volo 用于进行元信息透传的组件,定义了一套元信息透传的标准。 +- **Volo** 是 RPC 框架的名字,包含了 Volo-Thrift 和 Volo-gRPC 两部分。 +- **Volo-rs 组织** :Volo 的相关生态。 +- **Pilota** :Volo 使用的 Thrift 与 Protobuf 编译器及编解码的纯 Rust 实现(不依赖 protoc)。 +- **Motore** :Volo 参考 Tower 设计的,使用了 GAT 和 TAIT 的 middleware 抽象层。 +- **Metainfo** :Volo 用于进行元信息透传的组件,定义了一套元信息透传的标准。 全景图如下: @@ -230,11 +230,11 @@ Rust 以难学难用而闻名,我们希望尽可能地降低用户使用 [Volo 以下是所有相关生态的仓库地址。欢迎大家来提 Issue 或 PR,一起共建 [Volo][Volo]! -* Volo:https://github.com/cloudwego/volo -* Volo-rs:https://github.com/volo-rs -* Pilota:https://github.com/cloudwego/pilota -* Motore:https://github.com/cloudwego/motore -* Metainfo:https://github.com/cloudwego/metainfo +- Volo:https://github.com/cloudwego/volo +- Volo-rs:https://github.com/volo-rs +- Pilota:https://github.com/cloudwego/pilota +- Motore:https://github.com/cloudwego/motore +- Metainfo:https://github.com/cloudwego/metainfo ## Rust 语言和 Go 语言如何选择 @@ -268,19 +268,19 @@ Rust 以难学难用而闻名,我们希望尽可能地降低用户使用 [Volo 如果将 Rust 语言和 Go 语言单独做对比,我们应该如何解读它们呢?这是一个非常经典的问题。可以尝试从以下四方面考虑: -* **合作关系,取长补短** +- **合作关系,取长补短** 我们团队认为其实二者并不是对立关系,而是合作关系,它们是取长补短的。毕竟语言只是工具,很多时候我们只是需要一个更加得心应手的工具而已。 -* **(性能 >> 开发效率) || (安全性 >> 开发效率) -> Rust** +- **(性能 >> 开发效率) || (安全性 >> 开发效率) -> Rust** 对于需要极致性能,重计算的应用,以及需要稳定性并能接受一定开发速度损失的应用,推荐使用 Rust,Rust 在极致性能优化和安全性上的优势可以在这类应用中得以发挥。 -* **迭代速度要求高 -> Go** +- **迭代速度要求高 -> Go** 对于性能不敏感的应用、重 IO 的应用以及需要快速开发快速迭代胜过稳定性的应用,推荐使用 Go 语言,这种应用使用 Rust 并不会带来明显的收益。 -* **考虑团队技术储备和人才储备** +- **考虑团队技术储备和人才储备** 当然,还有一个很重要的考虑因素,是团队现有的技术栈,即技术储备和人才储备。 diff --git a/content/zh/blog/news/_index.md b/content/zh/blog/news/_index.md index 04f34787b4..f5b5e922ba 100644 --- a/content/zh/blog/news/_index.md +++ b/content/zh/blog/news/_index.md @@ -4,5 +4,3 @@ linkTitle: "新闻" projects: [] weight: 1 --- - - diff --git a/content/zh/blog/news/open_source_volo/index.md b/content/zh/blog/news/open_source_volo/index.md index 0738423c38..cda09239c3 100644 --- a/content/zh/blog/news/open_source_volo/index.md +++ b/content/zh/blog/news/open_source_volo/index.md @@ -69,7 +69,7 @@ Rust 以难学难用而闻名,我们希望尽可能降低用户使用 [Volo][V 比如,服务发现、负载均衡等服务治理功能,都可以以 Service 形式进行实现,而不需要独立实现 Trait。 -相关的扩展,我们会放在 github.com/volo-rs 组织下,也欢迎大家贡献自己的扩展到 volo-rs。 +相关的扩展,我们会放在 github.com/volo-rs 组织下,也欢迎大家贡献自己的扩展到 volo-rs。 ## 03 生态系统 @@ -97,13 +97,13 @@ Rust 以难学难用而闻名,我们希望尽可能降低用户使用 [Volo][V ### 参考资料 -* [Volo 概览](https://github.com/cloudwego/volo) +- [Volo 概览](https://github.com/cloudwego/volo) -* [Volo Tutorial](/zh/docs/volo/) +- [Volo Tutorial](/zh/docs/volo/) -* [Volo 文档](https://docs.rs/volo) +- [Volo 文档](https://docs.rs/volo) -* [Volo-rs 组织](https://github.com/volo-rs) +- [Volo-rs 组织](https://github.com/volo-rs) [Kitex]: https://github.com/cloudwego/kitex [Volo]: https://github.com/cloudwego/volo diff --git a/content/zh/blog/releases/Hertz/release-v010.md b/content/zh/blog/releases/Hertz/release-v010.md index df52e75059..b27968e49e 100644 --- a/content/zh/blog/releases/Hertz/release-v010.md +++ b/content/zh/blog/releases/Hertz/release-v010.md @@ -8,34 +8,33 @@ description: > ## Feature -* [[#70](https://github.com/cloudwego/hertz/pull/70)] feat: 增加 hz 脚手架。 -* [[#64](https://github.com/cloudwego/hertz/pull/64)] feat: 增加 Hertz Request & Response 到 net/http Request & ResponseWriter 的适配器。 -* [[#45](https://github.com/cloudwego/hertz/pull/45)] feat: 添加 ctx.Body() 方法。 -* [[#44](https://github.com/cloudwego/hertz/pull/44)] feat: 在 request header 上添加 VisitAllCustomHeader 方法,使得传入的函数 f 只作用在用户自定义的 header 上(除了 cookie, host, content-length, content-type, user-agent 和 connection 以外的 header)。 -* [[#59](https://github.com/cloudwego/hertz/pull/59)] feat: 支持 windows 开发环境。 +- [[#70](https://github.com/cloudwego/hertz/pull/70)] feat: 增加 hz 脚手架。 +- [[#64](https://github.com/cloudwego/hertz/pull/64)] feat: 增加 Hertz Request & Response 到 net/http Request & ResponseWriter 的适配器。 +- [[#45](https://github.com/cloudwego/hertz/pull/45)] feat: 添加 ctx.Body() 方法。 +- [[#44](https://github.com/cloudwego/hertz/pull/44)] feat: 在 request header 上添加 VisitAllCustomHeader 方法,使得传入的函数 f 只作用在用户自定义的 header 上(除了 cookie, host, content-length, content-type, user-agent 和 connection 以外的 header)。 +- [[#59](https://github.com/cloudwego/hertz/pull/59)] feat: 支持 windows 开发环境。 ## Refactor -* [[#37](https://github.com/cloudwego/hertz/pull/37)] refactor: 统一设置 request options 的入口,防止 options 未初始化导致 panic。 -* [[#52](https://github.com/cloudwego/hertz/pull/52)] refactor: 去掉 for 循环中多余的判空。 -* [[#33](https://github.com/cloudwego/hertz/pull/33)] refactor: +- [[#37](https://github.com/cloudwego/hertz/pull/37)] refactor: 统一设置 request options 的入口,防止 options 未初始化导致 panic。 +- [[#52](https://github.com/cloudwego/hertz/pull/52)] refactor: 去掉 for 循环中多余的判空。 +- [[#33](https://github.com/cloudwego/hertz/pull/33)] refactor: 当子串长度确定为 1 时,可以直接调用 strings.IndexByte 函数而不是像 strings.Index 一样先调用 len() 判断子串长度后再调用 strings.IndexByte 函数; 为省去整型数字转字符串的工作,可以将相关变量直接定义成 string 类型而不是 int 类型; net 包下的 JoinHostPort 函数会再次判断 ':' 是否在 addr 中,如果不在则将 host 与 port 相关字符串连接起来。然而在 AddingMissingPort 函数中调用 net.JoinHostPort 时,':' 应不在 addr 中。所以在此可以不调用 net.JoinHostPort,而是直接连接 host 和 port 信息。 -* [[#27](https://github.com/cloudwego/hertz/pull/27)] refactor: 当字符串不需要格式化时,使用 hertz 的 errors.NewPublic 创建 error 而不是使用 fmt.Errorf。 +- [[#27](https://github.com/cloudwego/hertz/pull/27)] refactor: 当字符串不需要格式化时,使用 hertz 的 errors.NewPublic 创建 error 而不是使用 fmt.Errorf。 ## Style -* [[#29](https://github.com/cloudwego/hertz/pull/29)] style(*): 修正拼写错误。 +- [[#29](https://github.com/cloudwego/hertz/pull/29)] style(\*): 修正拼写错误。 ## Optimize -* [[#57](https://github.com/cloudwego/hertz/pull/57)] optimize: 使用 http.TimeFormat 格式化 HTTP 中的 Date 信息,避免产生更多的复制。 -* [[#58](https://github.com/cloudwego/hertz/pull/58)] optimize: 服务端错误日志中添加对端地址。 -* [[#41](https://github.com/cloudwego/hertz/pull/41)] optimize(recovery): 使用 'CtxErrorf' 代替 'Errorf' 当服务 panic。 +- [[#57](https://github.com/cloudwego/hertz/pull/57)] optimize: 使用 http.TimeFormat 格式化 HTTP 中的 Date 信息,避免产生更多的复制。 +- [[#58](https://github.com/cloudwego/hertz/pull/58)] optimize: 服务端错误日志中添加对端地址。 +- [[#41](https://github.com/cloudwego/hertz/pull/41)] optimize(recovery): 使用 'CtxErrorf' 代替 'Errorf' 当服务 panic。 ## Docs -* [[#60](https://github.com/cloudwego/hertz/pull/60)] docs: readme 文件中添加 icon。 - +- [[#60](https://github.com/cloudwego/hertz/pull/60)] docs: readme 文件中添加 icon。 diff --git a/content/zh/blog/releases/Hertz/release-v020.md b/content/zh/blog/releases/Hertz/release-v020.md index eedd058627..fdc01ec9d1 100644 --- a/content/zh/blog/releases/Hertz/release-v020.md +++ b/content/zh/blog/releases/Hertz/release-v020.md @@ -8,41 +8,40 @@ description: > ## Feature -* [[#124](https://github.com/cloudwego/hertz/pull/124)] feat: 增加参数控制是否使用 hijackConnPool。 -* [[#116](https://github.com/cloudwego/hertz/pull/116)] feat: update 也可使用模板更新 handler 及 middleware。 -* [[#130](https://github.com/cloudwego/hertz/pull/130)] feat: 如果 Cookie.Value 中存在非法字符,则打印告警日志。 -* [[#143](https://github.com/cloudwego/hertz/pull/143)] feat: 增加一个接口支持自定义信号捕捉逻辑,以便根据场景调节优雅退出需要应对的信号类型。 -* [[#114](https://github.com/cloudwego/hertz/pull/114)] feat: 标准网络库 Read 方法中调用 connection.Release(),防止在多次少量调用 Read 方法时不回收内存导致的 OOM。 -* [[#112](https://github.com/cloudwego/hertz/pull/112)] feat: 修正了 x-www-form-urlencoded 编码下无法读到 bodystream 类型数据。 -* [[#105](https://github.com/cloudwego/hertz/pull/105)] feat: client 为 ALPN 和 http2 抽象出协议层 HostClient。client 删除 readbuffersize 和 writebuffersize 配置项。 -* [[#92](https://github.com/cloudwego/hertz/pull/92)] feat: hz 命名行工具支持 windows。 -* [[#102](https://github.com/cloudwego/hertz/pull/102)] feat: Hertz client 关闭默认的重试逻辑。 +- [[#124](https://github.com/cloudwego/hertz/pull/124)] feat: 增加参数控制是否使用 hijackConnPool。 +- [[#116](https://github.com/cloudwego/hertz/pull/116)] feat: update 也可使用模板更新 handler 及 middleware。 +- [[#130](https://github.com/cloudwego/hertz/pull/130)] feat: 如果 Cookie.Value 中存在非法字符,则打印告警日志。 +- [[#143](https://github.com/cloudwego/hertz/pull/143)] feat: 增加一个接口支持自定义信号捕捉逻辑,以便根据场景调节优雅退出需要应对的信号类型。 +- [[#114](https://github.com/cloudwego/hertz/pull/114)] feat: 标准网络库 Read 方法中调用 connection.Release(),防止在多次少量调用 Read 方法时不回收内存导致的 OOM。 +- [[#112](https://github.com/cloudwego/hertz/pull/112)] feat: 修正了 x-www-form-urlencoded 编码下无法读到 bodystream 类型数据。 +- [[#105](https://github.com/cloudwego/hertz/pull/105)] feat: client 为 ALPN 和 http2 抽象出协议层 HostClient。client 删除 readbuffersize 和 writebuffersize 配置项。 +- [[#92](https://github.com/cloudwego/hertz/pull/92)] feat: hz 命名行工具支持 windows。 +- [[#102](https://github.com/cloudwego/hertz/pull/102)] feat: Hertz client 关闭默认的重试逻辑。 ## Optimize -* [[#111](https://github.com/cloudwego/hertz/pull/111)] optimize: 调用 bytesconv.AppendHTTPDate 时,为切片预分配容量,以防止产生额外的拷贝。 -* [[#128](https://github.com/cloudwego/hertz/pull/128)] optimize: 去掉路由树中无用逻辑。 -* [[#108](https://github.com/cloudwego/hertz/pull/108)] optimize: 通过提前调用 regexp.MustCompile,避免程序重复解析正则表达式。 +- [[#111](https://github.com/cloudwego/hertz/pull/111)] optimize: 调用 bytesconv.AppendHTTPDate 时,为切片预分配容量,以防止产生额外的拷贝。 +- [[#128](https://github.com/cloudwego/hertz/pull/128)] optimize: 去掉路由树中无用逻辑。 +- [[#108](https://github.com/cloudwego/hertz/pull/108)] optimize: 通过提前调用 regexp.MustCompile,避免程序重复解析正则表达式。 ## Chore -* [[#125](https://github.com/cloudwego/hertz/pull/125)] chore: 更新 license check 方式。 +- [[#125](https://github.com/cloudwego/hertz/pull/125)] chore: 更新 license check 方式。 ## Fix -* [[#104](https://github.com/cloudwego/hertz/pull/104)] fix: cacheLock 可能会因潜在发生的 panic 导致解锁失败。 -* [[#96](https://github.com/cloudwego/hertz/pull/96)] fix: ci 可能被调度到 arm 机器上导致报错 exec format error。 +- [[#104](https://github.com/cloudwego/hertz/pull/104)] fix: cacheLock 可能会因潜在发生的 panic 导致解锁失败。 +- [[#96](https://github.com/cloudwego/hertz/pull/96)] fix: ci 可能被调度到 arm 机器上导致报错 exec format error。 ## Style -* [[#103](https://github.com/cloudwego/hertz/pull/103)] style: 修正不符合语义的错误拼写 “Ungzipped”。 -* [[#90](https://github.com/cloudwego/hertz/pull/90)] style: 常量替换和去掉了重复的类型转换。 +- [[#103](https://github.com/cloudwego/hertz/pull/103)] style: 修正不符合语义的错误拼写 “Ungzipped”。 +- [[#90](https://github.com/cloudwego/hertz/pull/90)] style: 常量替换和去掉了重复的类型转换。 ## Refactor -* [[#94](https://github.com/cloudwego/hertz/pull/94)] refactor: 使用 appendCookiePart 函数简化代码。 +- [[#94](https://github.com/cloudwego/hertz/pull/94)] refactor: 使用 appendCookiePart 函数简化代码。 ## Docs -* [[#97](https://github.com/cloudwego/hertz/pull/97)] docs: 文档标点符号优化。 - +- [[#97](https://github.com/cloudwego/hertz/pull/97)] docs: 文档标点符号优化。 diff --git a/content/zh/blog/releases/Hertz/release-v030.md b/content/zh/blog/releases/Hertz/release-v030.md index e021541d0e..ddc32f8d61 100644 --- a/content/zh/blog/releases/Hertz/release-v030.md +++ b/content/zh/blog/releases/Hertz/release-v030.md @@ -8,42 +8,41 @@ description: > ## Feature -* [[#182](https://github.com/cloudwego/hertz/pull/182)] feat: 添加服务注册 & 服务发现 & 负载均衡。 -* [[#6]](https://github.com/hertz-contrib/registry/pull/6) feat: 添加 zookeeper 服务注册与发现的扩展。 -* [[#7]](https://github.com/hertz-contrib/registry/pull/7) feat: 添加 nacos 服务注册与发现的扩展。 -* [[#8]](https://github.com/hertz-contrib/registry/pull/8) feat: 添加 Consul 服务注册与发现的扩展。 -* [[#9]](https://github.com/hertz-contrib/registry/pull/9) feat: 添加 polaris 服务注册与发现的扩展。 -* [[#14]](https://github.com/hertz-contrib/registry/pull/14) feat: 添加 etcd 服务注册与发现的扩展。 -* [[#15]](https://github.com/hertz-contrib/registry/pull/15) feat: 添加 servicecomb 服务注册与发现的扩展。 -* [[#16]](https://github.com/hertz-contrib/registry/pull/16) feat: 添加 eureka 服务注册与发现的扩展。 +- [[#182](https://github.com/cloudwego/hertz/pull/182)] feat: 添加服务注册 & 服务发现 & 负载均衡。 +- [[#6]](https://github.com/hertz-contrib/registry/pull/6) feat: 添加 zookeeper 服务注册与发现的扩展。 +- [[#7]](https://github.com/hertz-contrib/registry/pull/7) feat: 添加 nacos 服务注册与发现的扩展。 +- [[#8]](https://github.com/hertz-contrib/registry/pull/8) feat: 添加 Consul 服务注册与发现的扩展。 +- [[#9]](https://github.com/hertz-contrib/registry/pull/9) feat: 添加 polaris 服务注册与发现的扩展。 +- [[#14]](https://github.com/hertz-contrib/registry/pull/14) feat: 添加 etcd 服务注册与发现的扩展。 +- [[#15]](https://github.com/hertz-contrib/registry/pull/15) feat: 添加 servicecomb 服务注册与发现的扩展。 +- [[#16]](https://github.com/hertz-contrib/registry/pull/16) feat: 添加 eureka 服务注册与发现的扩展。 ## Refactor -* [[#175](https://github.com/cloudwego/hertz/pull/175)] refactor: 区别全局默认 dialer 和 client 局部 dialer(指定了 dialer 的 client 不再受全局 dialer 改变而改变)修改全局 dialer 影响面较大,标记 deprecated,后续统一到 client 初始化时传参指定 dialer 方式修改局部 dialer,以及移除了功能完全被 dialer 覆盖的 dialFunc 扩展。 +- [[#175](https://github.com/cloudwego/hertz/pull/175)] refactor: 区别全局默认 dialer 和 client 局部 dialer(指定了 dialer 的 client 不再受全局 dialer 改变而改变)修改全局 dialer 影响面较大,标记 deprecated,后续统一到 client 初始化时传参指定 dialer 方式修改局部 dialer,以及移除了功能完全被 dialer 覆盖的 dialFunc 扩展。 ## Optimize -* [[#205](https://github.com/cloudwego/hertz/pull/205)] optimize: 更改默认返回值。 +- [[#205](https://github.com/cloudwego/hertz/pull/205)] optimize: 更改默认返回值。 ## Test -* [[#174](https://github.com/cloudwego/hertz/pull/174)] test: 修正 TestRouterMiddlewareAndStatic 单测。 +- [[#174](https://github.com/cloudwego/hertz/pull/174)] test: 修正 TestRouterMiddlewareAndStatic 单测。 ## Fix -* [[#190](https://github.com/cloudwego/hertz/pull/190)] fix: 修改同名的路由组。 -* [[#192](https://github.com/cloudwego/hertz/pull/192)] fix: 修复 handler 中的引用相同包名的问题,并把获取 unique 变量名的方法单独提出来。 -* [[#208](https://github.com/cloudwego/hertz/pull/208)] fix: 当服务停止时修复取消注册失败。 -* [[#202](https://github.com/cloudwego/hertz/pull/202)] fix: 获取到了错误的 IPv6 本地回环地址。 -* [[#196](https://github.com/cloudwego/hertz/pull/196)] fix: 修复 typo。 -* [[#155](https://github.com/cloudwego/hertz/pull/155)] fix: 修复thrift的命名方式,struct name 与 thriftgo 的 namestyle 保持一致。 -* [[#169](https://github.com/cloudwego/hertz/pull/169)] fix: 修复 thrift 的 namespace 尾缀包含".thrift"的问题。 -* [[#184](https://github.com/cloudwego/hertz/pull/184)] fix: 修复使用标准网络库劫持连接时的超时错误。 -* [[#162](https://github.com/cloudwego/hertz/pull/162)] fix: 修复 IDL 中定义的路由最后一级为"/"时的报错。 +- [[#190](https://github.com/cloudwego/hertz/pull/190)] fix: 修改同名的路由组。 +- [[#192](https://github.com/cloudwego/hertz/pull/192)] fix: 修复 handler 中的引用相同包名的问题,并把获取 unique 变量名的方法单独提出来。 +- [[#208](https://github.com/cloudwego/hertz/pull/208)] fix: 当服务停止时修复取消注册失败。 +- [[#202](https://github.com/cloudwego/hertz/pull/202)] fix: 获取到了错误的 IPv6 本地回环地址。 +- [[#196](https://github.com/cloudwego/hertz/pull/196)] fix: 修复 typo。 +- [[#155](https://github.com/cloudwego/hertz/pull/155)] fix: 修复thrift的命名方式,struct name 与 thriftgo 的 namestyle 保持一致。 +- [[#169](https://github.com/cloudwego/hertz/pull/169)] fix: 修复 thrift 的 namespace 尾缀包含".thrift"的问题。 +- [[#184](https://github.com/cloudwego/hertz/pull/184)] fix: 修复使用标准网络库劫持连接时的超时错误。 +- [[#162](https://github.com/cloudwego/hertz/pull/162)] fix: 修复 IDL 中定义的路由最后一级为"/"时的报错。 ## Chore -* [[#189](https://github.com/cloudwego/hertz/pull/189)] 回滚 [cloudwego/hertz#162](https://github.com/cloudwego/hertz/pull/162) 的修改。 -* [[#203](https://github.com/cloudwego/hertz/pull/203)] AddMissingPort 函数增加对裸 v6 地址的处理。 -* [[#186](https://github.com/cloudwego/hertz/pull/186)] 支持 codecov。 - +- [[#189](https://github.com/cloudwego/hertz/pull/189)] 回滚 [cloudwego/hertz#162](https://github.com/cloudwego/hertz/pull/162) 的修改。 +- [[#203](https://github.com/cloudwego/hertz/pull/203)] AddMissingPort 函数增加对裸 v6 地址的处理。 +- [[#186](https://github.com/cloudwego/hertz/pull/186)] 支持 codecov。 diff --git a/content/zh/blog/releases/Hertz/release-v032.md b/content/zh/blog/releases/Hertz/release-v032.md index 77f6ee53f0..091e6dcf19 100644 --- a/content/zh/blog/releases/Hertz/release-v032.md +++ b/content/zh/blog/releases/Hertz/release-v032.md @@ -8,23 +8,22 @@ description: > ## Feature -* [[#198](https://github.com/cloudwego/hertz/pull/198)] feat: 添加获取 Hertz client dialer 名称的方法。 -* [[#251](https://github.com/cloudwego/hertz/pull/251)] feat: Hertz server 启动日志添加网络库的名称。 +- [[#198](https://github.com/cloudwego/hertz/pull/198)] feat: 添加获取 Hertz client dialer 名称的方法。 +- [[#251](https://github.com/cloudwego/hertz/pull/251)] feat: Hertz server 启动日志添加网络库的名称。 ## Refactor -* [[#238](https://github.com/cloudwego/hertz/pull/238)] refactor: 重构 Hertz client 初始化 HostClient 和 TLSHostClient 的逻辑。 +- [[#238](https://github.com/cloudwego/hertz/pull/238)] refactor: 重构 Hertz client 初始化 HostClient 和 TLSHostClient 的逻辑。 ## Optimize -* [[#226](https://github.com/cloudwego/hertz/pull/226)] optimize: 使用 "warning" 日志提示非法的 http 状态码。 +- [[#226](https://github.com/cloudwego/hertz/pull/226)] optimize: 使用 "warning" 日志提示非法的 http 状态码。 ## Fix -* [[#249](https://github.com/cloudwego/hertz/pull/249)] fix: 修复 Hertz server 优雅退出时无法执行完全部 hook 函数的问题。 -* [[#232](https://github.com/cloudwego/hertz/pull/232)] fix: 修复路由尾斜线重定向在边缘情况失效的问题。 +- [[#249](https://github.com/cloudwego/hertz/pull/249)] fix: 修复 Hertz server 优雅退出时无法执行完全部 hook 函数的问题。 +- [[#232](https://github.com/cloudwego/hertz/pull/232)] fix: 修复路由尾斜线重定向在边缘情况失效的问题。 ## Chore -* [[#217](https://github.com/cloudwego/hertz/pull/217)] chore: 更新提交 PR 时的填写模板。 - +- [[#217](https://github.com/cloudwego/hertz/pull/217)] chore: 更新提交 PR 时的填写模板。 diff --git a/content/zh/blog/releases/Hertz/release-v040.md b/content/zh/blog/releases/Hertz/release-v040.md index dcd8602b64..624f0f1d00 100644 --- a/content/zh/blog/releases/Hertz/release-v040.md +++ b/content/zh/blog/releases/Hertz/release-v040.md @@ -8,46 +8,45 @@ description: > ## Feature -* [[#289](https://github.com/cloudwego/hertz/pull/289)] feat: render 支持 IndentedJSON。 -* [[#304](https://github.com/cloudwego/hertz/pull/304)] feat: recovery 中间件支持用户自定义错误输出格式。 -* [[#278](https://github.com/cloudwego/hertz/pull/278)] feat: 增加编译 tag 控制实际使用的 json 库。 -* [[#239](https://github.com/cloudwego/hertz/pull/239)] feat: 给 client 扩展复杂重试能力。 -* [[#265](https://github.com/cloudwego/hertz/pull/265)] feat: 在标准网络库扩展上添加 CloseNoResetBuffer 方法。 -* [[#258](https://github.com/cloudwego/hertz/pull/258)] feat: 支持 `errors` 的格式化。 +- [[#289](https://github.com/cloudwego/hertz/pull/289)] feat: render 支持 IndentedJSON。 +- [[#304](https://github.com/cloudwego/hertz/pull/304)] feat: recovery 中间件支持用户自定义错误输出格式。 +- [[#278](https://github.com/cloudwego/hertz/pull/278)] feat: 增加编译 tag 控制实际使用的 json 库。 +- [[#239](https://github.com/cloudwego/hertz/pull/239)] feat: 给 client 扩展复杂重试能力。 +- [[#265](https://github.com/cloudwego/hertz/pull/265)] feat: 在标准网络库扩展上添加 CloseNoResetBuffer 方法。 +- [[#258](https://github.com/cloudwego/hertz/pull/258)] feat: 支持 `errors` 的格式化。 ## Optimize -* [[#295](https://github.com/cloudwego/hertz/pull/295)] optimize: 服务端忽略客户端主动断连的写错误。 -* [[#322](https://github.com/cloudwego/hertz/pull/322)] optimize: 修改 recovery 中间件的默认日志。 -* [[#266](https://github.com/cloudwego/hertz/pull/266)] optimize(hlog): 区分系统日志和默认日志,提供更自由的 logger 定制化能力。 -* [[#280](https://github.com/cloudwego/hertz/pull/280)] optimize: 使用标准库时 listen 前添加日志。 +- [[#295](https://github.com/cloudwego/hertz/pull/295)] optimize: 服务端忽略客户端主动断连的写错误。 +- [[#322](https://github.com/cloudwego/hertz/pull/322)] optimize: 修改 recovery 中间件的默认日志。 +- [[#266](https://github.com/cloudwego/hertz/pull/266)] optimize(hlog): 区分系统日志和默认日志,提供更自由的 logger 定制化能力。 +- [[#280](https://github.com/cloudwego/hertz/pull/280)] optimize: 使用标准库时 listen 前添加日志。 ## Refactor -* [[#318](https://github.com/cloudwego/hertz/pull/318)] refactor: 添加 SetRetryIf 保持兼容。 +- [[#318](https://github.com/cloudwego/hertz/pull/318)] refactor: 添加 SetRetryIf 保持兼容。 ## Test -* [[#299](https://github.com/cloudwego/hertz/pull/299)] test: 提高对 `hertz/pkg/protocol/header` 的单测覆盖率。 -* [[#290](https://github.com/cloudwego/hertz/pull/290)] test: 为 `pkg/app/server/option.go` 补充单元测试。 -* [[#274](https://github.com/cloudwego/hertz/pull/274)] test: 增加 internal/bytesconv 包测试覆盖率,覆盖率从 1.68% 提高到了 82.35%。 -* [[#285](https://github.com/cloudwego/hertz/pull/285)] test: 给 `pkg/protocol/request.go` 文件单测覆盖率 51.31% 提高到 85.3%。 -* [[#271](https://github.com/cloudwego/hertz/pull/271)] test: 为 `pkg/network` 补充单元测试。 -* [[#264](https://github.com/cloudwego/hertz/pull/264)] test: 增加对 `hertz/pkg/common/adaptor` 的单测,覆盖率从 76.6% 提高到了 92.3%。 -* [[#267](https://github.com/cloudwego/hertz/pull/267)] test(pkg/common/config): 增加 pkg/common/config 包测试覆盖率。 +- [[#299](https://github.com/cloudwego/hertz/pull/299)] test: 提高对 `hertz/pkg/protocol/header` 的单测覆盖率。 +- [[#290](https://github.com/cloudwego/hertz/pull/290)] test: 为 `pkg/app/server/option.go` 补充单元测试。 +- [[#274](https://github.com/cloudwego/hertz/pull/274)] test: 增加 internal/bytesconv 包测试覆盖率,覆盖率从 1.68% 提高到了 82.35%。 +- [[#285](https://github.com/cloudwego/hertz/pull/285)] test: 给 `pkg/protocol/request.go` 文件单测覆盖率 51.31% 提高到 85.3%。 +- [[#271](https://github.com/cloudwego/hertz/pull/271)] test: 为 `pkg/network` 补充单元测试。 +- [[#264](https://github.com/cloudwego/hertz/pull/264)] test: 增加对 `hertz/pkg/common/adaptor` 的单测,覆盖率从 76.6% 提高到了 92.3%。 +- [[#267](https://github.com/cloudwego/hertz/pull/267)] test(pkg/common/config): 增加 pkg/common/config 包测试覆盖率。 ## Docs -* [[#328](https://github.com/cloudwego/hertz/pull/328)] docs: 添加 lark 扩展到 readme.md。 -* [[#325](https://github.com/cloudwego/hertz/pull/325)] docs: 更新 README 和 README_cn 的性能数据。 -* [[#307](https://github.com/cloudwego/hertz/pull/307)] docs(README): 将 Hertz 扩展添加到 readme 列表中。 +- [[#328](https://github.com/cloudwego/hertz/pull/328)] docs: 添加 lark 扩展到 readme.md。 +- [[#325](https://github.com/cloudwego/hertz/pull/325)] docs: 更新 README 和 README_cn 的性能数据。 +- [[#307](https://github.com/cloudwego/hertz/pull/307)] docs(README): 将 Hertz 扩展添加到 readme 列表中。 ## Style -* [[#316](https://github.com/cloudwego/hertz/pull/316)] style: 去掉 license 顶层的空注释。 +- [[#316](https://github.com/cloudwego/hertz/pull/316)] style: 去掉 license 顶层的空注释。 ## Chore -* [[#272](https://github.com/cloudwego/hertz/pull/272)] chore: 更新 sonic 版本。 -* [[#310](https://github.com/cloudwego/hertz/pull/310)] chore: 修改注释信息为行注释避免 buildtag 格式问题的导致 ci 报错。 - +- [[#272](https://github.com/cloudwego/hertz/pull/272)] chore: 更新 sonic 版本。 +- [[#310](https://github.com/cloudwego/hertz/pull/310)] chore: 修改注释信息为行注释避免 buildtag 格式问题的导致 ci 报错。 diff --git a/content/zh/blog/releases/Hertz/release-v050.md b/content/zh/blog/releases/Hertz/release-v050.md index e41a5a3ad8..45240178e6 100644 --- a/content/zh/blog/releases/Hertz/release-v050.md +++ b/content/zh/blog/releases/Hertz/release-v050.md @@ -10,39 +10,45 @@ Hertz 0.5.0 版本中,除了常规迭代优化之外,我们还带来了多 ## 网络层和协议层支持基于流的接口 ->https://github.com/cloudwego/hertz/pull/467 +> https://github.com/cloudwego/hertz/pull/467 在 Hertz v0.5.0 版本中,我们进一步加强了 Hertz 传输层 & 协议层可扩展能力,支持无缝对接基于流的传输层协议 QUIC,以及在此之上构建的 [HTTP3 协议。](https://github.com/cloudwego/hertz/issues/458) 此外,我们在此基础上还增加和完善了 "ALPN"(应用层协议协商)、"QUIC/TLS parallel monitoring"(QUIC/TLS并行监听)、"Alt-Svc"(备选服务) 等功能。 ### 主要变更 + #### 传输层 + 我们在保证兼容性能的基础之上增加了一个针对基于流(stream-based)的网络连接接口抽象`StreamConn`,同时调整传输层和协议层的交互逻辑,实现针对连接类型的分发正确的协议层处理(protocol server)。 针对需要同时监听监听 TCP(TLS)以及 UDP(QUIC)的场景我们提供了一个`WithAltTransporter`选项,方便将备用 transporter 传递到主 transporter 中,便于实现 QUIC/TLS 并行监听的能力。 #### 协议层 + 支持添加基于流的协议层实现(protocol server)`StreamServer`,以便于在新增的基于流的传输层扩展之上构建对应处理协议(HTTP/3)。 为了便捷的实现为某个主协议(HTTP/3)配置备选服务元信息,`ProtocolSuite`对外暴露`SetAltHeader`接口。 同时,我们也为`StreamConn`设计了 ALPN 能力,以便于在 QUIC 内提供协议协商的能力。 #### 通用层 -同时我们在通用层中新增了能够与 Golang 标准 Handler 进行转换的辅助函数,以便于快速的将基于 Golang 标准 Handler 实现移植到 Hertz 中来。在之后提供的基于 [quic-go](https://github.com/lucas-clemente/quic-go) 的 [QUIC & HTTP/3 扩展](https://github.com/hertz-contrib/http3/pull/1)中,就用到了这个函数提供的能力。 +同时我们在通用层中新增了能够与 Golang 标准 Handler 进行转换的辅助函数,以便于快速的将基于 Golang 标准 Handler 实现移植到 Hertz 中来。在之后提供的基于 [quic-go](https://github.com/lucas-clemente/quic-go) 的 [QUIC & HTTP/3 扩展](https://github.com/hertz-contrib/http3/pull/1)中,就用到了这个函数提供的能力。 #### Feature 状态 -Hertz 核心库能力已经发布,具体实现后续将以[扩展包](https://github.com/hertz-contrib/http3/pull/1)的形式发布,欢迎试用~ +Hertz 核心库能力已经发布,具体实现后续将以[扩展包](https://github.com/hertz-contrib/http3/pull/1)的形式发布,欢迎试用~ 更多详细的设计说明可以参考:[Hertz 支持 QUIC & HTTP/3](/zh/blog/2023/08/02/hertz-%E6%94%AF%E6%8C%81-quic-http/3/) ## 脚手架工具支持生成 hertz client 代码 ->https://github.com/cloudwego/hertz/pull/471 + +> https://github.com/cloudwego/hertz/pull/471 在脚手架工具(Hz)的 v0.5.0 的版本,我们支持了基于 IDL 自动生成 hertz client 代码的功能,并实现了类 RPC 调用形式的 HTTP 请求一键调用。 使用方法: ->具体详见:https://github.com/cloudwego/hertz-examples/tree/main/hz_client + +> 具体详见:https://github.com/cloudwego/hertz-examples/tree/main/hz_client 1. 定义 IDL + ```go namespace go toutiao.middleware.hzClient @@ -61,16 +67,19 @@ service Hertz121 { api.base_domain="http://127.0.0.1:8888"; ) ``` + 2. 生成代码 可基于上述 IDL,分别生成 server 和 client 端代码: server: + ```go hz new --idl=psm.thrift --handler_by_method -t=template=slim ``` client: + ```go hz client --idl=psm.thrift --model_dir=hertz_gen -t=template=slim --client_dir=hz_client ``` @@ -80,5 +89,6 @@ hz client --idl=psm.thrift --model_dir=hertz_gen -t=template=slim --client_dir=h ## 完整 Release Note 完整的 Release Note 可以参考: -* Hertz: https://github.com/cloudwego/hertz/releases/tag/v0.5.0 -* Hz(脚手架): https://github.com/cloudwego/hertz/releases/tag/cmd%2Fhz%2Fv0.5.0 + +- Hertz: https://github.com/cloudwego/hertz/releases/tag/v0.5.0 +- Hz(脚手架): https://github.com/cloudwego/hertz/releases/tag/cmd%2Fhz%2Fv0.5.0 diff --git a/content/zh/blog/releases/Hertz/release-v060.md b/content/zh/blog/releases/Hertz/release-v060.md index 000d12e5f6..0c0945e765 100644 --- a/content/zh/blog/releases/Hertz/release-v060.md +++ b/content/zh/blog/releases/Hertz/release-v060.md @@ -9,10 +9,13 @@ description: > Hertz 0.6.0 版本中,除了常规迭代优化之外,我们还带来了多个重要 feature。 ## 支持 HTTP Trailer + 在 Hertz v0.6.0 版本中,我们支持了 HTTP Trailer 的编码和解析。 ->https://github.com/cloudwego/hertz-examples/tree/main/trailer -* 写 Trailer +> https://github.com/cloudwego/hertz-examples/tree/main/trailer + +- 写 Trailer + ```go // server 端 func handler(c context.Context, ctx *app.RequestContext){ @@ -22,7 +25,9 @@ func handler(c context.Context, ctx *app.RequestContext){ // client 端 req.Header.Trailer().Set("Hertz", "Good") ``` -* 读 Trailer + +- 读 Trailer + ```go // server 端 func handler(c context.Context, ctx *app.RequestContext){ @@ -34,29 +39,37 @@ resp.Header.Trailer().Get("Hertz") ``` ## HTTP/1.1 支持 Response Writer 劫持 + 在 Hertz v0.6.0 版本中,我们扩展了 HTTP/1.1 写请求的方式,在原来写请求流程的基础之上,支持用户在业务 handler/中间件中劫持 Response Writer,实现更加灵活的写请求方式。 简单来说,原来所有的“底层写”逻辑统一放到 handler/中间件返回之后,这个带来两个比较明显的局限性: + 1. 用户无法控制请求真正 flush 到对端的时机 2. 针对 chunk 方式增量产生数据 & 实时写到对端的场景,在老的架构之上用法相对复杂,限制相对较多 基于此我们扩展出一套能够提供自行 flush 请求头和请求体的能力,同时提供了一个支持用户按需发送 chunk 数据的 Writer。详细实现参考:https://github.com/cloudwego/hertz/pull/610 ### 主要变更 + 1. 增加了一个扩展 Writer 的接口定义,实现了这个接口的 Writer 都可以用作劫持 Response Writer: - ```go - type ExtWriter interface { - io.Writer - Flush() error - - // Finalize will be called by framework before the writer is released. - // Implementations must guarantee that Finalize is safe for multiple calls. - Finalize() error - } - ``` + + ```go + type ExtWriter interface { + io.Writer + Flush() error + + // Finalize will be called by framework before the writer is released. + // Implementations must guarantee that Finalize is safe for multiple calls. + Finalize() error + } + ``` + 2. 提供了一个实现了上述接口的 Chunk Writer(有类似需求都可以参考这个来实现):`chunkedBodyWrite` 3. HTTP/1.1 具体写请求的地方针对被劫持了 Writer 的 Response 写操作做了对应的处理(跳过默认写请求逻辑),最后调用`ExtWriter`接口的`Finalize()`方法完成一次请求写回 + ### 使用方法 + 如上,Hertz 提供了一个默认的`ExtWriter`实现满足用户在 handler/中间件中的主动 flush 需求,使用方式也非常简单: + ```go h.GET("/flush/chunk", func(c context.Context, ctx *app.RequestContext) { // Hijack the writer of response @@ -75,14 +88,16 @@ h.GET("/flush/chunk", func(c context.Context, ctx *app.RequestContext) { 在 hz v0.6.0 版本中,我们对生成代码的组织结构进行一系列的优化,从而可生成更加灵活的代码组织结构 ### 主要优化 -* `new` 命令支持 "router_dir" 选项,并配合已有的 "handler_dir"、"model_dir",可完全自定义 IDL 生成产物的路径;并且会将这些自定义选项持久化到 ".hz" 文件中,可在 `update` 时自动读取,减少命令的复杂度 -* 增加向上搜索 "go.mod" 文件的能力,从而使得 hertz 在作为一个子项目时可以和其他项目共享同一个 "go module" -* 增加 "handler" 中引用第三方 IDL 产物的能力,可将 IDL 产物放到第三方仓库单独维护,使其不在项目目录中存放,进一步增强 IDL 管理能力 + +- `new` 命令支持 "router_dir" 选项,并配合已有的 "handler_dir"、"model_dir",可完全自定义 IDL 生成产物的路径;并且会将这些自定义选项持久化到 ".hz" 文件中,可在 `update` 时自动读取,减少命令的复杂度 +- 增加向上搜索 "go.mod" 文件的能力,从而使得 hertz 在作为一个子项目时可以和其他项目共享同一个 "go module" +- 增加 "handler" 中引用第三方 IDL 产物的能力,可将 IDL 产物放到第三方仓库单独维护,使其不在项目目录中存放,进一步增强 IDL 管理能力 ### 最佳实践 我们利用 "hz v0.6.0" 重写了 "[biz-demo/easy-note](https://github.com/cloudwego/biz-demo/pull/26)",主要利用了如下 hz 的特性 -- 利用 "hz client" 的能力,基于 IDL 生成访问 "api server" 的 hertz client 调用代码 + +- 利用 "hz client" 的能力,基于 IDL 生成访问 "api server" 的 hertz client 调用代码 - 利用自定义 "router_dir"、 "handler_dir"、"model_dir" 选项,重新调整 "api server" 代码的组织结构,去掉 "biz" 目录的限制 - 利用 "向上搜索 go.mod" 的能力,使得 "api server" 可以作为 "easy-note" 的子项目共享同一个 "go module" - 利用 "handler 引用第三方 IDL 产物" 的能力并配合 "hz model" 的能力,使得 IDL 产物单独存到到 "easy-note" 项目里,而并不存放到 "api server" 子项目里 @@ -90,5 +105,6 @@ h.GET("/flush/chunk", func(c context.Context, ctx *app.RequestContext) { ## 完整 Release Note 完整的 Release Note 可以参考: -* Hertz: https://github.com/cloudwego/hertz/releases/tag/v0.6.0 -* Hz(脚手架): https://github.com/cloudwego/hertz/releases/tag/cmd%2Fhz%2Fv0.6.0 + +- Hertz: https://github.com/cloudwego/hertz/releases/tag/v0.6.0 +- Hz(脚手架): https://github.com/cloudwego/hertz/releases/tag/cmd%2Fhz%2Fv0.6.0 diff --git a/content/zh/blog/releases/Hertz/release-v070.md b/content/zh/blog/releases/Hertz/release-v070.md index 4f09cd565b..d606022203 100644 --- a/content/zh/blog/releases/Hertz/release-v070.md +++ b/content/zh/blog/releases/Hertz/release-v070.md @@ -9,23 +9,28 @@ description: > Hertz v0.7.0 版本中,除了常规迭代优化之外,我们还带来了一个重要 feature。 ## 参数绑定重构 + 在 Hertz v0.7.0 版本中,我们重构了 hertz 参数绑定 ->https://github.com/cloudwego/hertz/pull/541 + +> https://github.com/cloudwego/hertz/pull/541 ### 重构说明 + 在 Hertz v0.7.0 版本中,我们重构了参数绑定能力,将参数绑定能力收敛到框架本身,以更好地支持用户的需求。本次重构主要有以下特点: -* 功能一致: - - Binder:重构后在 Hertz 内部实现了一个默认的 Binder,其功能与重构前完全对齐,并将重构前的绑定能力以拓展的形式实现在 hertz-contrib 下 - - Validator: 仍使用 go-tagexpr 作为默认实现,保证功能一致 -* 配置收敛: - - 重构前:参数绑定的行为大多通过全局参数的形式进行配置,可能导致多个组件出现配置冲突 - - 重构后:以 BindConfig 和 ValidateConfig 的结构通过 'WithOption' 的形式注入到 Hertz Engine 中,既能统一配置形式,又能避免配置冲突的问题 -* 可自定义 Binder 和 Validator: - - 自定义 Binder:可使用 "WithCustomBinder" 来注入自定义的 Binder,目前已有拓展 hertz-contrib/binding/go_tagexpr - - 自定义 Validator:可使用 "WithCustomValidator" 来注入自定义的 Validator,目前已经将 go-playground/validator 进行了拓展 -* 性能提升:重构后绑定性能较之前有提升,详见后文压测数据 + +- 功能一致: + - Binder:重构后在 Hertz 内部实现了一个默认的 Binder,其功能与重构前完全对齐,并将重构前的绑定能力以拓展的形式实现在 hertz-contrib 下 + - Validator: 仍使用 go-tagexpr 作为默认实现,保证功能一致 +- 配置收敛: + - 重构前:参数绑定的行为大多通过全局参数的形式进行配置,可能导致多个组件出现配置冲突 + - 重构后:以 BindConfig 和 ValidateConfig 的结构通过 'WithOption' 的形式注入到 Hertz Engine 中,既能统一配置形式,又能避免配置冲突的问题 +- 可自定义 Binder 和 Validator: + - 自定义 Binder:可使用 "WithCustomBinder" 来注入自定义的 Binder,目前已有拓展 hertz-contrib/binding/go_tagexpr + - 自定义 Validator:可使用 "WithCustomValidator" 来注入自定义的 Validator,目前已经将 go-playground/validator 进行了拓展 +- 性能提升:重构后绑定性能较之前有提升,详见后文压测数据 ### 使用方法 + ```go package main @@ -44,8 +49,10 @@ func main() { ``` ### 压测数据 + https://github.com/cloudwego/hertz-benchmark/tree/main/binding 完整的 Release Note 可以参考: -* Hertz: https://github.com/cloudwego/hertz/releases/tag/v0.7.0 -* Hz(脚手架): https://github.com/cloudwego/hertz/releases/tag/cmd%2Fhz%2Fv0.7.0 + +- Hertz: https://github.com/cloudwego/hertz/releases/tag/v0.7.0 +- Hz(脚手架): https://github.com/cloudwego/hertz/releases/tag/cmd%2Fhz%2Fv0.7.0 diff --git a/content/zh/blog/releases/Hertz/release-v080.md b/content/zh/blog/releases/Hertz/release-v080.md index 6fb7faf049..fb774bc531 100644 --- a/content/zh/blog/releases/Hertz/release-v080.md +++ b/content/zh/blog/releases/Hertz/release-v080.md @@ -9,14 +9,18 @@ description: > Hertz v0.8.0 版本中,除了常规迭代优化之外,我们还带来了一个重要 feature。 ## Partitioned cookies + 在 Hertz v0.8.0 版本中,我们支持了 partitioned cookies 特性。 ->https://github.com/cloudwego/hertz/pull/1041 + +> https://github.com/cloudwego/hertz/pull/1041 ### 背景 + 三方 Cookie 为 Web 提供了跨站点跟踪的能力,它的存在为 Web 用户的隐私和安全都带来了巨大威胁。Chrome 从 2024 年第一季度开始对 1% 的用户禁用第三方 Cookie,从 2024 年第三季度开始逐步将禁用范围扩大到 100%。 Partitioned Cookies Cookies Having Independent Partitioned State (CHIPS) 作为三方Cookie的替代方案,提供了跨站(cross-site)请求携带三方 Cookie 的能力。 #### 通过 Set-Cookie Header 设置 Partitioned Cookie + ``` Set-Cookie header: Set-Cookie: __Host-name=value; Secure; Path=/; SameSite=None; Partitioned; @@ -25,10 +29,13 @@ Set-Cookie: __Host-name=value; Secure; Path=/; SameSite=None; Partitioned; ### How to #### 升级 Hertz 版本 + Hertz 在 v0.8.0 添加了对 Partitioned Cookies 的支持,你需要升级到>=v0.8.0来使用 Partitioned Cookie。 -#### 如何使用 Partitioned Cookies +#### 如何使用 Partitioned Cookies + 目前 Hertz 支持 Partitioned Cookies,但还不支持通过 SetCookie 传入是否为 Partitioned,我们将在下个小版本增加此功能。在此之前,你可以参考下面的代码示例来使用 Partitioned Cookies。 + ``` func SetPartitionedCookie(ctx *app.RequestContext, name, value string, maxAge int, path, domain string, sameSite protocol.CookieSameSite, secure, httpOnly bool) { if path == "" { @@ -61,6 +68,7 @@ func main() { h.Spin() } ``` + 验证 Set-Cookie Header ``` @@ -80,5 +88,5 @@ curl -v http://localhost:8888/partitioned < Set-Cookie: user=hertz; max-age=1; domain=localhost; path=/; HttpOnly; secure; SameSite=None; Partitioned < * Connection #0 to host localhost left intact -{"partitioned":"yes"}% -``` \ No newline at end of file +{"partitioned":"yes"}% +``` diff --git a/content/zh/blog/releases/Kitex/_index.md b/content/zh/blog/releases/Kitex/_index.md index 8cad80ba7e..c86ebc7203 100644 --- a/content/zh/blog/releases/Kitex/_index.md +++ b/content/zh/blog/releases/Kitex/_index.md @@ -3,4 +3,4 @@ title: "Kitex Release" linkTitle: "Kitex" projects: ["Kitex"] weight: 1 ---- \ No newline at end of file +--- diff --git a/content/zh/blog/releases/Kitex/release-v001.md b/content/zh/blog/releases/Kitex/release-v001.md index 40b094a956..1f1b6190f3 100755 --- a/content/zh/blog/releases/Kitex/release-v001.md +++ b/content/zh/blog/releases/Kitex/release-v001.md @@ -4,7 +4,6 @@ linkTitle: "Release v0.0.1" projects: ["Kitex"] date: 2021-07-12 description: > - --- -Kitex 项目初始化。 \ No newline at end of file +Kitex 项目初始化。 diff --git a/content/zh/blog/releases/Kitex/release-v002.md b/content/zh/blog/releases/Kitex/release-v002.md index da991a641c..7f774e38e8 100644 --- a/content/zh/blog/releases/Kitex/release-v002.md +++ b/content/zh/blog/releases/Kitex/release-v002.md @@ -4,7 +4,6 @@ linkTitle: "Release v0.0.2" projects: ["Kitex"] date: 2021-07-30 description: > - --- ## 优化: @@ -17,7 +16,6 @@ description: > - 修复了一个 lbcache 中 nil-pointer 的错误。 - 修复了一个 retry 重试(Backup Request)中的 data race 问题。 - ## 工具: - Kitex 工具去掉默认生成的配置文件。 diff --git a/content/zh/blog/releases/Kitex/release-v003.md b/content/zh/blog/releases/Kitex/release-v003.md index 61d9eefa4c..aa492c0e48 100644 --- a/content/zh/blog/releases/Kitex/release-v003.md +++ b/content/zh/blog/releases/Kitex/release-v003.md @@ -4,8 +4,8 @@ linkTitle: "Release v0.0.3" projects: ["Kitex"] date: 2021-08-01 description: > - --- + ## Bug 修复: -- 防止连接池被覆盖。 \ No newline at end of file +- 防止连接池被覆盖。 diff --git a/content/zh/blog/releases/Kitex/release-v004.md b/content/zh/blog/releases/Kitex/release-v004.md index 3403f81fed..24970b6652 100644 --- a/content/zh/blog/releases/Kitex/release-v004.md +++ b/content/zh/blog/releases/Kitex/release-v004.md @@ -23,8 +23,7 @@ description: > - 调整了 Protobuf unary 方法的生成代码,来同时支持 Kitex Protobuf 和 gRPC。 - 升级了 thriftgo 版本来修复 golint。 - 修复了生成代码中的错误。 -- 修复了流生成的代码缺少传输选项的错误。 - +- 修复了流生成的代码缺少传输选项的错误。 ## 文档: @@ -33,5 +32,6 @@ description: > - 添加了一些英文文档。 ## 依赖变化: + 1. Thriftgo: v0.0.2-0.20210726073420-0145861fcd04 -> v0.1.2 2. Netpoll: v0.0.2 -> v0.0.3 diff --git a/content/zh/blog/releases/Kitex/release-v005.md b/content/zh/blog/releases/Kitex/release-v005.md index 6151932be9..d9c697d64c 100644 --- a/content/zh/blog/releases/Kitex/release-v005.md +++ b/content/zh/blog/releases/Kitex/release-v005.md @@ -4,7 +4,6 @@ linkTitle: "Release v0.0.5" projects: ["Kitex"] date: 2021-09-26 description: > - --- ## 功能: diff --git a/content/zh/blog/releases/Kitex/release-v008.md b/content/zh/blog/releases/Kitex/release-v008.md index 8b29c74897..70d83bc114 100644 --- a/content/zh/blog/releases/Kitex/release-v008.md +++ b/content/zh/blog/releases/Kitex/release-v008.md @@ -6,29 +6,29 @@ date: 2021-11-05 description: > --- -## 优化 +## 优化 - 使用分片 ring 减少连接池的锁开销。 - 装填 TTHeader 中的上游服务信息到 rpcinfo 中,用于在 decode 出错时输出来源信息。 - Unlink uds 调整至 CreateListener 中。 -- event.go 和 ring_single.go 中的 Mutex 改为 RWMutex。 +- event.go 和 ring_single.go 中的 Mutex 改为 RWMutex。 -## Bug 修复 +## Bug 修复 - 修复 netpollmux shard index 溢出的问题。 - 移除 `WithCircuitBreaker` option 里对参数的反射,避免 data-race。 - 在重试场景下, 修复 rpc finish 错误导致的小概率失败的问题,并且加上了熔断 sample 的校验。 - 修复 endpoint_test.go 中的一处单测错误。 -- 修改 conn_wrapper.go 中 longconn 变量命名为 conn.。 +- 修改 conn_wrapper.go 中 longconn 变量命名为 conn.。 -## 生成工具 +## 生成工具 -- 代码生成工具支持透传thrift-go插件参数。 +- 代码生成工具支持透传thrift-go插件参数。 -## 文档 +## 文档 - 将 README 中的性能结果改为引用 kitex-benchmark 仓库的数据。 -## 依赖变化 +## 依赖变化 - github.com/tidwall/gjson: v1.8.0 -> v1.9.3 diff --git a/content/zh/blog/releases/Kitex/release-v010.md b/content/zh/blog/releases/Kitex/release-v010.md index cb4562d7ba..3826ca9a01 100644 --- a/content/zh/blog/releases/Kitex/release-v010.md +++ b/content/zh/blog/releases/Kitex/release-v010.md @@ -4,69 +4,67 @@ linkTitle: "Release v0.1.0" projects: ["Kitex"] date: 2021-12-13 description: > - --- -## 功能 +## 功能 -### 泛化调用 +### 泛化调用 -* IDL 解析支持多 Service -* 暴露 SetSeqID 方法便于二进制泛化场景 server 侧使用 -* 泛化 client 支持关闭,规避内存泄漏问题 +- IDL 解析支持多 Service +- 暴露 SetSeqID 方法便于二进制泛化场景 server 侧使用 +- 泛化 client 支持关闭,规避内存泄漏问题 -### 日志 +### 日志 -* 修改日志风格,使用 "key=value" 列出信息 -* 使用 klog 作为全局的日志输出工具 -* 使用全局的 default logger -* 日志打印更多 context 信息,例如 logId,方便问题排查 -* go func 传入服务信息用于 recover panic 后输出关键信息方便问题排查 +- 修改日志风格,使用 "key=value" 列出信息 +- 使用 klog 作为全局的日志输出工具 +- 使用全局的 default logger +- 日志打印更多 context 信息,例如 logId,方便问题排查 +- go func 传入服务信息用于 recover panic 后输出关键信息方便问题排查 -### Option +### Option -* 增加 NewThriftCodecDisableFastMode 方法,来关闭 FastWrite 和 FastRead -* Kitex server 支持端口复用 -* 默认 RPC 超时设置为 0(在后续 PR 中,revert 了该变更) +- 增加 NewThriftCodecDisableFastMode 方法,来关闭 FastWrite 和 FastRead +- Kitex server 支持端口复用 +- 默认 RPC 超时设置为 0(在后续 PR 中,revert 了该变更) -### Proxy +### Proxy -* Proxy 增加 ContextHandler 接口用于传递初始化ctx给 mwbuilder -* 注册 lbcache 的 Dump 给 diagnosis,用于问题诊断 -* 将 PRCConfig 传递给 proxy.Config +- Proxy 增加 ContextHandler 接口用于传递初始化ctx给 mwbuilder +- 注册 lbcache 的 Dump 给 diagnosis,用于问题诊断 +- 将 PRCConfig 传递给 proxy.Config -## 优化 +## 优化 -* 减少了对象的堆分配 -* 优化多路复用性能 -* 优化 grpc 编解码性能,通过 Release 时释放(Close) LinkBuffer -* 在计算 backup request 的消耗(cost)时,区分 ErrRPCFinish -* 多路复用分片队列逻辑移动至 netpoll/mux,并重命名分片字典 -* 优化Fast api中容器类型的长度编码逻辑 +- 减少了对象的堆分配 +- 优化多路复用性能 +- 优化 grpc 编解码性能,通过 Release 时释放(Close) LinkBuffer +- 在计算 backup request 的消耗(cost)时,区分 ErrRPCFinish +- 多路复用分片队列逻辑移动至 netpoll/mux,并重命名分片字典 +- 优化Fast api中容器类型的长度编码逻辑 -## Bug 修复 +## Bug 修复 -* 修复 server 端 WithErrorHandler 配置不生效问题 -* 调整 lbcache 中的 Balancer 初始化逻辑 -* 修复 TraceCtl 可能为 nil 的问题(仅影响单测) -* 设置默认的 rpc timeout, 并支持设置 WithRPCTimeout(0) 来关闭超时中间件 -* 修复 default logger 使用错误的 call depth -* 重命名 BackwardProxy 为 ReverseProxy -* 修复 grpc 场景下的 panic -* 修复 grpc 场景下的潜在风险(keepalive 超时导致 panic) -* 修复 void 方法中的异常缺失 -* 修复实例变更时 dump 信息不正确问题。 +- 修复 server 端 WithErrorHandler 配置不生效问题 +- 调整 lbcache 中的 Balancer 初始化逻辑 +- 修复 TraceCtl 可能为 nil 的问题(仅影响单测) +- 设置默认的 rpc timeout, 并支持设置 WithRPCTimeout(0) 来关闭超时中间件 +- 修复 default logger 使用错误的 call depth +- 重命名 BackwardProxy 为 ReverseProxy +- 修复 grpc 场景下的 panic +- 修复 grpc 场景下的潜在风险(keepalive 超时导致 panic) +- 修复 void 方法中的异常缺失 +- 修复实例变更时 dump 信息不正确问题。 ## 文档 -* 修复失效的中文链接 -* 将全部 doc 移至官网 cloudwego.io +- 修复失效的中文链接 +- 将全部 doc 移至官网 cloudwego.io ## Netpoll API Change: -* 适应 netpoll.Writer.Append 的 API 改动,返回值从 2个 变为 1个 +- 适应 netpoll.Writer.Append 的 API 改动,返回值从 2个 变为 1个 -## 依赖变化 - -* github.com/cloudwego/netpoll: v0.0.4 -> v0.1.2 +## 依赖变化 +- github.com/cloudwego/netpoll: v0.0.4 -> v0.1.2 diff --git a/content/zh/blog/releases/Kitex/release-v012.md b/content/zh/blog/releases/Kitex/release-v012.md index 7d480226c5..4021a89dd4 100644 --- a/content/zh/blog/releases/Kitex/release-v012.md +++ b/content/zh/blog/releases/Kitex/release-v012.md @@ -4,18 +4,17 @@ linkTitle: "Release v0.1.2" projects: ["Kitex"] date: 2021-12-22 description: > - --- ## Hotfix -* 修复 v0.1.0 gRPC 请求优化引入的部分问题 -* 修复 IDL 中未定义 package 时,gRPC 的方法信息错误问题 +- 修复 v0.1.0 gRPC 请求优化引入的部分问题 +- 修复 IDL 中未定义 package 时,gRPC 的方法信息错误问题 ## 依赖更新 -* 更新 netpoll-http2 依赖,解决 streaming 场景下大包(>4K)请求报错的问题 +- 更新 netpoll-http2 依赖,解决 streaming 场景下大包(>4K)请求报错的问题 ## 杂项 -* 使用 GitHub 的 PR 模板,强制开发者提交 PR 时填写相关描述 +- 使用 GitHub 的 PR 模板,强制开发者提交 PR 时填写相关描述 diff --git a/content/zh/blog/releases/Kitex/release-v013.md b/content/zh/blog/releases/Kitex/release-v013.md index 7b8187fc9f..a6832b5d27 100644 --- a/content/zh/blog/releases/Kitex/release-v013.md +++ b/content/zh/blog/releases/Kitex/release-v013.md @@ -4,23 +4,22 @@ linkTitle: "Release v0.1.3" projects: ["Kitex"] date: 2021-12-30 description: > - --- ## 功能优化 -* JSON 泛化调用场景,向服务端传递 Base 信息,从而服务端可获取 Caller 等信息 +- JSON 泛化调用场景,向服务端传递 Base 信息,从而服务端可获取 Caller 等信息 ## Bug 修复 -* 修复 streaming 的 metric 上报(server侧)丢失 method 信息的问题 -* 修复 JSON 和 HTTP 泛化中 base64 和 binary 的不兼容改动 -* 修复 gRPC 流控相关的问题,该问题会导致 client 侧出现持续超时 +- 修复 streaming 的 metric 上报(server侧)丢失 method 信息的问题 +- 修复 JSON 和 HTTP 泛化中 base64 和 binary 的不兼容改动 +- 修复 gRPC 流控相关的问题,该问题会导致 client 侧出现持续超时 ## CI -* 增加场景测试 +- 增加场景测试 ## Chore -* 更新了 [ROADMAP](https://github.com/cloudwego/kitex/blob/develop/ROADMAP.md) +- 更新了 [ROADMAP](https://github.com/cloudwego/kitex/blob/develop/ROADMAP.md) diff --git a/content/zh/blog/releases/Kitex/release-v014.md b/content/zh/blog/releases/Kitex/release-v014.md index d25e6e5fe3..a8cd700e99 100644 --- a/content/zh/blog/releases/Kitex/release-v014.md +++ b/content/zh/blog/releases/Kitex/release-v014.md @@ -4,27 +4,25 @@ linkTitle: "Release v0.1.4" projects: ["Kitex"] date: 2022-01-18 description: > - --- ## 功能优化 -* 在 rpctimeout 的 middleware 的输出日志中过滤掉超时日志 -* 调整默认日志级别为 Info -* 给 sentAt 变量加锁,避免单测出现 DATA RACE,实际上不会有并发问题 +- 在 rpctimeout 的 middleware 的输出日志中过滤掉超时日志 +- 调整默认日志级别为 Info +- 给 sentAt 变量加锁,避免单测出现 DATA RACE,实际上不会有并发问题 ## Bug 修复 -* 修复客户端编码失败时连接会泄漏的问题 -* 修复 middleware builder 中设置 TimeoutAdjust 不生效的问题 - +- 修复客户端编码失败时连接会泄漏的问题 +- 修复 middleware builder 中设置 TimeoutAdjust 不生效的问题 ## 工具 -* 修复 protobuf 的 handler 参数名 -> kitex 会给每个 stream server 生成一个名为 "{{.ServiceName}}_{{.Name}}Server" 的 stream 类型, -> 但是在 handler.go 中使用的是 "{{.ServiceName}}_{{.RawName}}Server +- 修复 protobuf 的 handler 参数名 + > kitex 会给每个 stream server 生成一个名为 "{{.ServiceName}}_{{.Name}}Server" 的 stream 类型, + > 但是在 handler.go 中使用的是 "{{.ServiceName}}_{{.RawName}}Server ## Chore -* 删除不必要的类型转换 +- 删除不必要的类型转换 diff --git a/content/zh/blog/releases/Kitex/release-v020.md b/content/zh/blog/releases/Kitex/release-v020.md index bb2eda679c..3c69292515 100644 --- a/content/zh/blog/releases/Kitex/release-v020.md +++ b/content/zh/blog/releases/Kitex/release-v020.md @@ -4,28 +4,27 @@ linkTitle: "Release v0.2.0" projects: ["Kitex"] date: 2022-02-24 description: > - --- ## Feature -* Feat(grpc): gRPC 相关配置支持通过 options 来设置,并且为了兼容旧版本默认窗口大小调整为 64K -* Feat(kerror): 为 basicError 添加新的 error 封装 func WithCauseAndExtraMsg -* Feat(rpcinfo): 添加 FreezeRPCInfo 以支持异步 context 使用 -* Feat(codec): 默认编解码器支持限定包体积大小 +- Feat(grpc): gRPC 相关配置支持通过 options 来设置,并且为了兼容旧版本默认窗口大小调整为 64K +- Feat(kerror): 为 basicError 添加新的 error 封装 func WithCauseAndExtraMsg +- Feat(rpcinfo): 添加 FreezeRPCInfo 以支持异步 context 使用 +- Feat(codec): 默认编解码器支持限定包体积大小 ## Bugfix -* Fix(remotecli): 修复重置的连接可能被复用的问题 -* Fix(generic): 修复泛化调用的客户端不能使用继承的 service 的方法的问题 -* Fix(generic): 修复泛化调用 client 侧判断 Oneway 不准确的问题 +- Fix(remotecli): 修复重置的连接可能被复用的问题 +- Fix(generic): 修复泛化调用的客户端不能使用继承的 service 的方法的问题 +- Fix(generic): 修复泛化调用 client 侧判断 Oneway 不准确的问题 ## Optimise -* Optimize(retry): 提高异常重试的重试成功率 -> 如果超时的请求先于重试的请求返回,可能会导致重试请求也失败;同时也可以避免超时请求不必要的解码处理。 +- Optimize(retry): 提高异常重试的重试成功率 + > 如果超时的请求先于重试的请求返回,可能会导致重试请求也失败;同时也可以避免超时请求不必要的解码处理。 ## Chore -* Chore: 升级 netpoll 的版本至 v0.2.0 -* Chore: 添加第三方库的license +- Chore: 升级 netpoll 的版本至 v0.2.0 +- Chore: 添加第三方库的license diff --git a/content/zh/blog/releases/Kitex/release-v021.md b/content/zh/blog/releases/Kitex/release-v021.md index 09bf33a101..c8c0fd0e5e 100644 --- a/content/zh/blog/releases/Kitex/release-v021.md +++ b/content/zh/blog/releases/Kitex/release-v021.md @@ -4,33 +4,32 @@ linkTitle: "Release v0.2.1" projects: ["Kitex"] date: 2022-03-24 description: > - --- ## Bugfix -* [[#383](https://github.com/cloudwego/kitex/pull/383) ] 修复(generic):在泛化调用的时候检查 IDL 是否有循环依赖。 -* [[#359](https://github.com/cloudwego/kitex/pull/359) ] 修复(tool):修复 protobuf CombineService 缺失 streaming 引用的问题。 -* [[#363](https://github.com/cloudwego/kitex/pull/363) ] 修复(client):修复 oneway 请求的 sequence ID 没有被编码的问题以及降低 oneway 调用的丢包率。 -* [[#367](https://github.com/cloudwego/kitex/pull/367) ] 修复(generic/tool):修复 CombineServices 可能存在多次加载同一个 service 问题。 +- [[#383](https://github.com/cloudwego/kitex/pull/383) ] 修复(generic):在泛化调用的时候检查 IDL 是否有循环依赖。 +- [[#359](https://github.com/cloudwego/kitex/pull/359) ] 修复(tool):修复 protobuf CombineService 缺失 streaming 引用的问题。 +- [[#363](https://github.com/cloudwego/kitex/pull/363) ] 修复(client):修复 oneway 请求的 sequence ID 没有被编码的问题以及降低 oneway 调用的丢包率。 +- [[#367](https://github.com/cloudwego/kitex/pull/367) ] 修复(generic/tool):修复 CombineServices 可能存在多次加载同一个 service 问题。 ## Optimise -* [[#362](https://github.com/cloudwego/kitex/pull/362) ] 优化(diagnosis):lbcaches 是全局的,无需为每个 client 注册 ProbeFunc 用于诊断查询。 -* [[#374](https://github.com/cloudwego/kitex/pull/374) ] 优化(rpcinfo):RPCInfo.To().Tag() 优先使用服务发现的 instance tag 而不是 remoteinfo tag。 -* [[#355](https://github.com/cloudwego/kitex/pull/355) ] 优化(连接池):修改默认的连接池最小空闲等待时间为 2s。 -* [[#354](https://github.com/cloudwego/kitex/pull/354) ] 优化(hook):为 `onServerStart`和 `onShutdown`添加资源锁,当做一些如`RegisterStartHook`和 `server.Run`中的 `range`之类的读写操作时请求对应的资源锁。 -* [[#331](https://github.com/cloudwego/kitex/pull/331) ] 优化(discovery):增加「实例不存在」错误定义。 +- [[#362](https://github.com/cloudwego/kitex/pull/362) ] 优化(diagnosis):lbcaches 是全局的,无需为每个 client 注册 ProbeFunc 用于诊断查询。 +- [[#374](https://github.com/cloudwego/kitex/pull/374) ] 优化(rpcinfo):RPCInfo.To().Tag() 优先使用服务发现的 instance tag 而不是 remoteinfo tag。 +- [[#355](https://github.com/cloudwego/kitex/pull/355) ] 优化(连接池):修改默认的连接池最小空闲等待时间为 2s。 +- [[#354](https://github.com/cloudwego/kitex/pull/354) ] 优化(hook):为 `onServerStart`和 `onShutdown`添加资源锁,当做一些如`RegisterStartHook`和 `server.Run`中的 `range`之类的读写操作时请求对应的资源锁。 +- [[#331](https://github.com/cloudwego/kitex/pull/331) ] 优化(discovery):增加「实例不存在」错误定义。 ## Refactor -* [[#352](https://github.com/cloudwego/kitex/pull/352) ] 重构(event):删除额外的原子操作并用普通赋值操作替换。 -* [[#343](https://github.com/cloudwego/kitex/pull/343) ] 重构(loadbalancer):将 buildWeightedVirtualNodes 函数合入 buildVirtualNodes 函数中,成为一个函数。 +- [[#352](https://github.com/cloudwego/kitex/pull/352) ] 重构(event):删除额外的原子操作并用普通赋值操作替换。 +- [[#343](https://github.com/cloudwego/kitex/pull/343) ] 重构(loadbalancer):将 buildWeightedVirtualNodes 函数合入 buildVirtualNodes 函数中,成为一个函数。 ## Chore -* [[#376](https://github.com/cloudwego/kitex/pull/376) ] 升级依赖 choleraehyq/pid 以兼容Go 1.18。 +- [[#376](https://github.com/cloudwego/kitex/pull/376) ] 升级依赖 choleraehyq/pid 以兼容Go 1.18。 ## Docs -* [[#364](https://github.com/cloudwego/kitex/pull/364) ] 更新 README 到新博客的链接。 +- [[#364](https://github.com/cloudwego/kitex/pull/364) ] 更新 README 到新博客的链接。 diff --git a/content/zh/blog/releases/Kitex/release-v030.md b/content/zh/blog/releases/Kitex/release-v030.md index 648c381bef..d02330509a 100644 --- a/content/zh/blog/releases/Kitex/release-v030.md +++ b/content/zh/blog/releases/Kitex/release-v030.md @@ -4,48 +4,47 @@ linkTitle: "Release v0.3.0" projects: ["Kitex"] date: 2022-04-29 description: > - --- ## Feature -* [[#366](https://github.com/cloudwego/kitex/pull/366), [#426](https://github.com/cloudwego/kitex/pull/426) ] 功能(client): 客户端支持预热操作 -* [[#395](https://github.com/cloudwego/kitex/pull/395) ] 功能(mux): 连接多路复用支持优雅关闭 -* [[#399](https://github.com/cloudwego/kitex/pull/399) ] 功能(protobuf): 定义 fastpb protocol API 并在编解码模块对应支持 +- [[#366](https://github.com/cloudwego/kitex/pull/366), [#426](https://github.com/cloudwego/kitex/pull/426) ] 功能(client): 客户端支持预热操作 +- [[#395](https://github.com/cloudwego/kitex/pull/395) ] 功能(mux): 连接多路复用支持优雅关闭 +- [[#399](https://github.com/cloudwego/kitex/pull/399) ] 功能(protobuf): 定义 fastpb protocol API 并在编解码模块对应支持 ## Optimise -* [[#402](https://github.com/cloudwego/kitex/pull/402) ] 优化(connpool): 导出 pkg/remote/connpool 里的 getCommonReporter -* [[#389](https://github.com/cloudwego/kitex/pull/389) ] 优化(rpcinfo):填充由 defaultCodec 解码得到的 rpcinfo 中缺失的 Invocation().PackageName, Invocation().ServiceName and Config().TransportProtocol 字段 +- [[#402](https://github.com/cloudwego/kitex/pull/402) ] 优化(connpool): 导出 pkg/remote/connpool 里的 getCommonReporter +- [[#389](https://github.com/cloudwego/kitex/pull/389) ] 优化(rpcinfo):填充由 defaultCodec 解码得到的 rpcinfo 中缺失的 Invocation().PackageName, Invocation().ServiceName and Config().TransportProtocol 字段 ## Bugfix -* [[#413](https://github.com/cloudwego/kitex/pull/413) ] 修复(mux): 在 NetpollMux transHandler 中设置 sendMsg的PayloadCodec,以修复泛化请求编码报错问题[issue #411](https://github.com/cloudwego/kitex/issues/411) -* [[#406](https://github.com/cloudwego/kitex/pull/406) ] 修复(grpc): 修复 http2 framer 的读写逻辑,例如避免对端无法及时收到 framer -* [[#398](https://github.com/cloudwego/kitex/pull/398) ] 修复(utils):修复了 Dump() 接口无法 dump 出 ring 里所有数据的 bug -* [[#428](https://github.com/cloudwego/kitex/pull/428) ] 修复(trans):当写入失败时,关闭连接以避免内存泄漏 +- [[#413](https://github.com/cloudwego/kitex/pull/413) ] 修复(mux): 在 NetpollMux transHandler 中设置 sendMsg的PayloadCodec,以修复泛化请求编码报错问题[issue #411](https://github.com/cloudwego/kitex/issues/411) +- [[#406](https://github.com/cloudwego/kitex/pull/406) ] 修复(grpc): 修复 http2 framer 的读写逻辑,例如避免对端无法及时收到 framer +- [[#398](https://github.com/cloudwego/kitex/pull/398) ] 修复(utils):修复了 Dump() 接口无法 dump 出 ring 里所有数据的 bug +- [[#428](https://github.com/cloudwego/kitex/pull/428) ] 修复(trans):当写入失败时,关闭连接以避免内存泄漏 ## Tool -* [[#340](https://github.com/cloudwego/kitex/pull/340) ] tool(protobuf): 重新设计并实现 Protobuf 生成代码,不使用反射完成编解码,当前仅支持 proto3 +- [[#340](https://github.com/cloudwego/kitex/pull/340) ] tool(protobuf): 重新设计并实现 Protobuf 生成代码,不使用反射完成编解码,当前仅支持 proto3 ## Chore -* [[#396](https://github.com/cloudwego/kitex/pull/396) ] chore: 用 bytedance/gopkg 里的 xxhash3 替换掉 cespare/xxhash -* [[#400](https://github.com/cloudwego/kitex/pull/400) ] chore: 升级 workflow 的 go 版本到 1.18 -* [[#407](https://github.com/cloudwego/kitex/pull/407) ] chore: 单独增加文件对 grpc 源码使用做声明 +- [[#396](https://github.com/cloudwego/kitex/pull/396) ] chore: 用 bytedance/gopkg 里的 xxhash3 替换掉 cespare/xxhash +- [[#400](https://github.com/cloudwego/kitex/pull/400) ] chore: 升级 workflow 的 go 版本到 1.18 +- [[#407](https://github.com/cloudwego/kitex/pull/407) ] chore: 单独增加文件对 grpc 源码使用做声明 ## Test -* [[#401](https://github.com/cloudwego/kitex/pull/401) ] test: 补充 kitex/server 的单测 -* [[#393](https://github.com/cloudwego/kitex/pull/393) ] test: 补充 pkg/remote/bound package 单测 -* [[#403](https://github.com/cloudwego/kitex/pull/403) ] test: 补充 netpollmux package 单测 -* [[#401](https://github.com/cloudwego/kitex/pull/401) ] test: 补充 klog package 单测 -* [[#392](https://github.com/cloudwego/kitex/pull/392) ] test: 补充 utils package 单测 -* [[#373](https://github.com/cloudwego/kitex/pull/373), [#432](https://github.com/cloudwego/kitex/pull/432), [#434](https://github.com/cloudwego/kitex/pull/434) ] test: 补充 gRPC transport 部分的单测,单测覆盖率提升到 76% -* [[#424](https://github.com/cloudwego/kitex/pull/424) ] test: 补充 transmeta 实现 handler 的单元测试 +- [[#401](https://github.com/cloudwego/kitex/pull/401) ] test: 补充 kitex/server 的单测 +- [[#393](https://github.com/cloudwego/kitex/pull/393) ] test: 补充 pkg/remote/bound package 单测 +- [[#403](https://github.com/cloudwego/kitex/pull/403) ] test: 补充 netpollmux package 单测 +- [[#401](https://github.com/cloudwego/kitex/pull/401) ] test: 补充 klog package 单测 +- [[#392](https://github.com/cloudwego/kitex/pull/392) ] test: 补充 utils package 单测 +- [[#373](https://github.com/cloudwego/kitex/pull/373), [#432](https://github.com/cloudwego/kitex/pull/432), [#434](https://github.com/cloudwego/kitex/pull/434) ] test: 补充 gRPC transport 部分的单测,单测覆盖率提升到 76% +- [[#424](https://github.com/cloudwego/kitex/pull/424) ] test: 补充 transmeta 实现 handler 的单元测试 ## Dependency Change -* github.com/cloudwego/netpoll: v0.2.0 -> v0.2.2 -* github.com/bytedance/gopkg: 20210910103821-e4efae9c17c3 -> 20220413063733-65bf48ffb3a7 +- github.com/cloudwego/netpoll: v0.2.0 -> v0.2.2 +- github.com/bytedance/gopkg: 20210910103821-e4efae9c17c3 -> 20220413063733-65bf48ffb3a7 diff --git a/content/zh/blog/releases/Kitex/release-v032.md b/content/zh/blog/releases/Kitex/release-v032.md index 8c7816c209..fb35f8a671 100644 --- a/content/zh/blog/releases/Kitex/release-v032.md +++ b/content/zh/blog/releases/Kitex/release-v032.md @@ -4,59 +4,57 @@ linkTitle: "Release v0.3.2" projects: ["Kitex"] date: 2022-06-02 description: > - --- ## Feature -* [[#473](https://github.com/cloudwego/kitex/pull/473)] 功能 (grpc): 为 Kitex gRPC unary 模式增加短连接功能。 -* [[#431](https://github.com/cloudwego/kitex/pull/431)] 功能 (limiter): +- [[#473](https://github.com/cloudwego/kitex/pull/473)] 功能 (grpc): 为 Kitex gRPC unary 模式增加短连接功能。 +- [[#431](https://github.com/cloudwego/kitex/pull/431)] 功能 (limiter): 1. 支持自定义的限流实现,接口增加了请求参数的传递; 2. 修复多路复用场景下 Server 的 QPS 限流器问题,添加基于 OnMessage 的限流; 3. 调整默认的限流生效时机,只有使用框架 QPS 限流且非多路复用的场景下,才使用基于 OnRead 的限流。 ## Optimize -* [[#465](https://github.com/cloudwego/kitex/pull/465)] 优化 (ttheader): Client 端在 TTHeader 解码结束后赋值 Remote Address (用于 Proxy 场景请求失败时获取对端地址)。 -* [[#466](https://github.com/cloudwego/kitex/pull/466)] 优化 (mux): 连接多路复用场景的 ErrReadTimeout 用 ErrRPCTimeout 封装返回。Proxy 场景请求失败时获取对端地址)。 -* [[#425](https://github.com/cloudwego/kitex/pull/425)] 优化 (limiter): 优化限流实现,保证第一秒的 Tokens 不会大幅超过限制。 +- [[#465](https://github.com/cloudwego/kitex/pull/465)] 优化 (ttheader): Client 端在 TTHeader 解码结束后赋值 Remote Address (用于 Proxy 场景请求失败时获取对端地址)。 +- [[#466](https://github.com/cloudwego/kitex/pull/466)] 优化 (mux): 连接多路复用场景的 ErrReadTimeout 用 ErrRPCTimeout 封装返回。Proxy 场景请求失败时获取对端地址)。 +- [[#425](https://github.com/cloudwego/kitex/pull/425)] 优化 (limiter): 优化限流实现,保证第一秒的 Tokens 不会大幅超过限制。 ## Bugfix -* [[#485](https://github.com/cloudwego/kitex/pull/485)] 修复 (grpc): 修复 grpc 内不恰当的 int 类型转换。 -* [[#474](https://github.com/cloudwego/kitex/pull/474)] 修复 (trans): 在 detection handler 中增加检测。当 OnInactive 比 OnActive 先发生,或者 OnActive 返回 error 时,防止空指针 panic。 -* [[#445](https://github.com/cloudwego/kitex/pull/445)] 修复 (retry): +- [[#485](https://github.com/cloudwego/kitex/pull/485)] 修复 (grpc): 修复 grpc 内不恰当的 int 类型转换。 +- [[#474](https://github.com/cloudwego/kitex/pull/474)] 修复 (trans): 在 detection handler 中增加检测。当 OnInactive 比 OnActive 先发生,或者 OnActive 返回 error 时,防止空指针 panic。 +- [[#445](https://github.com/cloudwego/kitex/pull/445)] 修复 (retry): 1. 修复重试中 `callTimes` 字段的 race 问题; 2. 修复 `rpcStats` 中一些字段的 race 问题。 -* [[#471](https://github.com/cloudwego/kitex/pull/471)] 修复 (retry): 修复在 backup request 中的一个 race 问题。 +- [[#471](https://github.com/cloudwego/kitex/pull/471)] 修复 (retry): 修复在 backup request 中的一个 race 问题。 ## Test -* [[#404](https://github.com/cloudwego/kitex/pull/404)] test: 增加 pkg/retry 的单测。 -* [[#439](https://github.com/cloudwego/kitex/pull/439), [#472](https://github.com/cloudwego/kitex/pull/472)] test: 增加 pkg/remote/remotecli 的单测。 -* [[#462](https://github.com/cloudwego/kitex/pull/462), [#457](https://github.com/cloudwego/kitex/pull/457)] test: 增加 pkg/remote/trans/nphttp2/grpc 的单测。 -* [[#420](https://github.com/cloudwego/kitex/pull/420)] test: 增加 pkg/remote/trans/nphttp2 的单测。 +- [[#404](https://github.com/cloudwego/kitex/pull/404)] test: 增加 pkg/retry 的单测。 +- [[#439](https://github.com/cloudwego/kitex/pull/439), [#472](https://github.com/cloudwego/kitex/pull/472)] test: 增加 pkg/remote/remotecli 的单测。 +- [[#462](https://github.com/cloudwego/kitex/pull/462), [#457](https://github.com/cloudwego/kitex/pull/457)] test: 增加 pkg/remote/trans/nphttp2/grpc 的单测。 +- [[#420](https://github.com/cloudwego/kitex/pull/420)] test: 增加 pkg/remote/trans/nphttp2 的单测。 ## Refactor -* [[#464](https://github.com/cloudwego/kitex/pull/464)] refactor (ttheader): 修改 Kitex Protobuf 在 TTHeader 中的 protocolID,同时保证该变更与低版本的兼容性。 +- [[#464](https://github.com/cloudwego/kitex/pull/464)] refactor (ttheader): 修改 Kitex Protobuf 在 TTHeader 中的 protocolID,同时保证该变更与低版本的兼容性。 ## Chore -* [[#453](https://github.com/cloudwego/kitex/pull/453), [#475](https://github.com/cloudwego/kitex/pull/475)] chore: 更新 netpoll 和 bytedance/gopkg 的版本。 -* [[#458](https://github.com/cloudwego/kitex/pull/458)] chore: 修复了 reviewdog 失效的问题与 fork pr 单测的问题。 -* [[#454](https://github.com/cloudwego/kitex/pull/454)] chore: 现在的 CI 受限于 github runner 的性能经常会失败,尝试改成 self-hosted runner 来提升性能。 -* [[#449](https://github.com/cloudwego/kitex/pull/449)] chore: 更新 issue template,修改为更适合 Kitex 项目的问题模板。 +- [[#453](https://github.com/cloudwego/kitex/pull/453), [#475](https://github.com/cloudwego/kitex/pull/475)] chore: 更新 netpoll 和 bytedance/gopkg 的版本。 +- [[#458](https://github.com/cloudwego/kitex/pull/458)] chore: 修复了 reviewdog 失效的问题与 fork pr 单测的问题。 +- [[#454](https://github.com/cloudwego/kitex/pull/454)] chore: 现在的 CI 受限于 github runner 的性能经常会失败,尝试改成 self-hosted runner 来提升性能。 +- [[#449](https://github.com/cloudwego/kitex/pull/449)] chore: 更新 issue template,修改为更适合 Kitex 项目的问题模板。 ## Style -* [[#486](https://github.com/cloudwego/kitex/pull/486)] style (trans): 为 detection trans handler 增加注释信息。 +- [[#486](https://github.com/cloudwego/kitex/pull/486)] style (trans): 为 detection trans handler 增加注释信息。 ## Docs -* [[#482](https://github.com/cloudwego/kitex/pull/482)] docs: 在 Readme 中增加 FAQ 链接。 +- [[#482](https://github.com/cloudwego/kitex/pull/482)] docs: 在 Readme 中增加 FAQ 链接。 ## Dependency Change -* github.com/cloudwego/netpoll: v0.2.2 -> v0.2.4 - +- github.com/cloudwego/netpoll: v0.2.2 -> v0.2.4 diff --git a/content/zh/blog/releases/Kitex/release-v040.md b/content/zh/blog/releases/Kitex/release-v040.md index 82a6925523..befcd8a789 100644 --- a/content/zh/blog/releases/Kitex/release-v040.md +++ b/content/zh/blog/releases/Kitex/release-v040.md @@ -22,59 +22,59 @@ description: > 1. **性能优化**:gRPC Unary 吞吐提升 46-70%,相比官方 gRPC 吞吐高 51%-70%,详见 [benchmark ](https://github.com/cloudwego/kitex-benchmark) 2. **泛化调用**:HTTP / Map / JSON 泛化调用支持了 Thrift 默认值 ----- +--- ## 详细变更 ### Feature -* [[#571](https://github.com/cloudwego/kitex/pull/571)] 功能(protobuf): 默认集成 [fastpb](https://github.com/cloudwego/fastpb) 到 Kitex,详情参考 [doc](/docs/kitex/tutorials/code-gen/fastpb/)。 -* [[#592](https://github.com/cloudwego/kitex/pull/592)] 功能(generic): HTTP/Map/JSON 泛化调用支持 Thrift 默认值。 -* [[#600](https://github.com/cloudwego/kitex/pull/600)] 功能(thrift): 支持当使用 frugal 时不生成编解码代码。 -* [[#607](https://github.com/cloudwego/kitex/pull/607), [#610](https://github.com/cloudwego/kitex/pull/610)] 功能(proxyless): 提供 xDS 扩展的接口。支持基于 xDS 的流量路由,超时配置及服务发现。 -* [[#541](https://github.com/cloudwego/kitex/pull/541)] 功能(trans): 传输层增加 go net 作为扩展,并在 Windows OS 下作为默认网络库。 -* [[#540](https://github.com/cloudwego/kitex/pull/540)] 功能(retry): Retry 支持指定 error 或 resp 重试,同时新增 option 用来支持为方法设置重试策略。 -* [[#533](https://github.com/cloudwego/kitex/pull/533)] 功能(generic): 泛化调用 js_conv 注解支持 map 类型转换。 +- [[#571](https://github.com/cloudwego/kitex/pull/571)] 功能(protobuf): 默认集成 [fastpb](https://github.com/cloudwego/fastpb) 到 Kitex,详情参考 [doc](/docs/kitex/tutorials/code-gen/fastpb/)。 +- [[#592](https://github.com/cloudwego/kitex/pull/592)] 功能(generic): HTTP/Map/JSON 泛化调用支持 Thrift 默认值。 +- [[#600](https://github.com/cloudwego/kitex/pull/600)] 功能(thrift): 支持当使用 frugal 时不生成编解码代码。 +- [[#607](https://github.com/cloudwego/kitex/pull/607), [#610](https://github.com/cloudwego/kitex/pull/610)] 功能(proxyless): 提供 xDS 扩展的接口。支持基于 xDS 的流量路由,超时配置及服务发现。 +- [[#541](https://github.com/cloudwego/kitex/pull/541)] 功能(trans): 传输层增加 go net 作为扩展,并在 Windows OS 下作为默认网络库。 +- [[#540](https://github.com/cloudwego/kitex/pull/540)] 功能(retry): Retry 支持指定 error 或 resp 重试,同时新增 option 用来支持为方法设置重试策略。 +- [[#533](https://github.com/cloudwego/kitex/pull/533)] 功能(generic): 泛化调用 js_conv 注解支持 map 类型转换。 ### Optimize -* [[#522](https://github.com/cloudwego/kitex/pull/522), [#538](https://github.com/cloudwego/kitex/pull/538), [#605](https://github.com/cloudwego/kitex/pull/605)] 优化(grpc): 优化 gRPC 协议性能。 -* [[#590](https://github.com/cloudwego/kitex/pull/590)] 优化(tool): 支持从文件扩展名猜测 IDL 的类型。 -* [[#559](https://github.com/cloudwego/kitex/pull/559)] 优化(timeout): 在超时中间件中使用超时封装方法判断底层超时,用来忽略一些定制超时错误日志。 -* [[#581](https://github.com/cloudwego/kitex/pull/581)] 优化(tool): Kitex 命令增加使用示例。 +- [[#522](https://github.com/cloudwego/kitex/pull/522), [#538](https://github.com/cloudwego/kitex/pull/538), [#605](https://github.com/cloudwego/kitex/pull/605)] 优化(grpc): 优化 gRPC 协议性能。 +- [[#590](https://github.com/cloudwego/kitex/pull/590)] 优化(tool): 支持从文件扩展名猜测 IDL 的类型。 +- [[#559](https://github.com/cloudwego/kitex/pull/559)] 优化(timeout): 在超时中间件中使用超时封装方法判断底层超时,用来忽略一些定制超时错误日志。 +- [[#581](https://github.com/cloudwego/kitex/pull/581)] 优化(tool): Kitex 命令增加使用示例。 ### Bugfix -* [[#564](https://github.com/cloudwego/kitex/pull/564)] 修复(oneway): 当 oneway 请求发送完毕后,关闭对应的连接,否则后续的发送到该连接上的请求会被阻塞在 server 端,直到 server 端把上一个 oneway 请求处理完。 -* [[#577](https://github.com/cloudwego/kitex/pull/577), [#584](https://github.com/cloudwego/kitex/pull/584), [#602](https://github.com/cloudwego/kitex/pull/602)] 修复(rpcinfo): 修复长连接场景下 rpcinfo 复用问题。 -* [[#578](https://github.com/cloudwego/kitex/pull/578)] 修复: 修复 long pool dump 可能导致 panic 的问题。 -* [[#583](https://github.com/cloudwego/kitex/pull/583)] 修复(tool): 修复 protobuf 生成代码引用了错误的 package 名字的问题 -* [[#587](https://github.com/cloudwego/kitex/pull/587)] 修复(tool): 生成代码的时候跳过指定了外部 import path 的 proto 文件。 -* [[#594](https://github.com/cloudwego/kitex/pull/594)] 修复(generic): 泛化调用支持单引号中双引号带转义符的 tag 格式以兼容旧版本逻辑。 -* [[#595](https://github.com/cloudwego/kitex/pull/595)] 修复: 修复 union 为 nil 时 BLength 会 panic 的问题。 -* [[#589](https://github.com/cloudwego/kitex/pull/589), [#596](https://github.com/cloudwego/kitex/pull/596)] 修复(frugal): 修复 frugal build tag。 +- [[#564](https://github.com/cloudwego/kitex/pull/564)] 修复(oneway): 当 oneway 请求发送完毕后,关闭对应的连接,否则后续的发送到该连接上的请求会被阻塞在 server 端,直到 server 端把上一个 oneway 请求处理完。 +- [[#577](https://github.com/cloudwego/kitex/pull/577), [#584](https://github.com/cloudwego/kitex/pull/584), [#602](https://github.com/cloudwego/kitex/pull/602)] 修复(rpcinfo): 修复长连接场景下 rpcinfo 复用问题。 +- [[#578](https://github.com/cloudwego/kitex/pull/578)] 修复: 修复 long pool dump 可能导致 panic 的问题。 +- [[#583](https://github.com/cloudwego/kitex/pull/583)] 修复(tool): 修复 protobuf 生成代码引用了错误的 package 名字的问题 +- [[#587](https://github.com/cloudwego/kitex/pull/587)] 修复(tool): 生成代码的时候跳过指定了外部 import path 的 proto 文件。 +- [[#594](https://github.com/cloudwego/kitex/pull/594)] 修复(generic): 泛化调用支持单引号中双引号带转义符的 tag 格式以兼容旧版本逻辑。 +- [[#595](https://github.com/cloudwego/kitex/pull/595)] 修复: 修复 union 为 nil 时 BLength 会 panic 的问题。 +- [[#589](https://github.com/cloudwego/kitex/pull/589), [#596](https://github.com/cloudwego/kitex/pull/596)] 修复(frugal): 修复 frugal build tag。 ### Refactor -* [[#566](https://github.com/cloudwego/kitex/pull/566)] refactor(metainfo): 移除 HTTP2 header 中没有使用的 meta keys。 -* [[#593](https://github.com/cloudwego/kitex/pull/593)] refactor(trans): 服务端支持通过 WithListener 配置 listener,其优先级高于 WithServiceAddr。 -* [[#582](https://github.com/cloudwego/kitex/pull/582)] refactor(tool): kitex 工具以文件嵌入方式使用模板并导出部分 API 供外部使用。 +- [[#566](https://github.com/cloudwego/kitex/pull/566)] refactor(metainfo): 移除 HTTP2 header 中没有使用的 meta keys。 +- [[#593](https://github.com/cloudwego/kitex/pull/593)] refactor(trans): 服务端支持通过 WithListener 配置 listener,其优先级高于 WithServiceAddr。 +- [[#582](https://github.com/cloudwego/kitex/pull/582)] refactor(tool): kitex 工具以文件嵌入方式使用模板并导出部分 API 供外部使用。 ### Test -* [[#579](https://github.com/cloudwego/kitex/pull/579)] test: 长连接池 dump 增加单测。 -* [[#608](https://github.com/cloudwego/kitex/pull/608)] test: 修复 TestClientConnDecoupledFromApplicationRead 的 data race 问题。 -* [[#609](https://github.com/cloudwego/kitex/pull/609)] test: 修复 gonet 单测中的端口冲突问题。 -* [[#480](https://github.com/cloudwego/kitex/pull/480)] test: 给 client package 增加单测。 +- [[#579](https://github.com/cloudwego/kitex/pull/579)] test: 长连接池 dump 增加单测。 +- [[#608](https://github.com/cloudwego/kitex/pull/608)] test: 修复 TestClientConnDecoupledFromApplicationRead 的 data race 问题。 +- [[#609](https://github.com/cloudwego/kitex/pull/609)] test: 修复 gonet 单测中的端口冲突问题。 +- [[#480](https://github.com/cloudwego/kitex/pull/480)] test: 给 client package 增加单测。 ### Chore -* [[#558](https://github.com/cloudwego/kitex/pull/558)] ci: 修复 ci 中 setup-python 的问题。 -* [[#487](https://github.com/cloudwego/kitex/pull/487)] ci: Workflow 中增加 golangci-lint。 -* [[#580](https://github.com/cloudwego/kitex/pull/580)] chore: 修复 remote 模块中 go net 相关的错误拼写。 -* [[#601](https://github.com/cloudwego/kitex/pull/601)] chore: 修复错误拼写并替换掉一些功能重复的代码。 -* [[#604](https://github.com/cloudwego/kitex/pull/604)] chore: 升级 fastpb 到 v0.0.2。 -* [[#603](https://github.com/cloudwego/kitex/pull/603)] chore: 升级 frugal 到 v0.1.2。 +- [[#558](https://github.com/cloudwego/kitex/pull/558)] ci: 修复 ci 中 setup-python 的问题。 +- [[#487](https://github.com/cloudwego/kitex/pull/487)] ci: Workflow 中增加 golangci-lint。 +- [[#580](https://github.com/cloudwego/kitex/pull/580)] chore: 修复 remote 模块中 go net 相关的错误拼写。 +- [[#601](https://github.com/cloudwego/kitex/pull/601)] chore: 修复错误拼写并替换掉一些功能重复的代码。 +- [[#604](https://github.com/cloudwego/kitex/pull/604)] chore: 升级 fastpb 到 v0.0.2。 +- [[#603](https://github.com/cloudwego/kitex/pull/603)] chore: 升级 frugal 到 v0.1.2。 ### Dependency Change @@ -93,6 +93,3 @@ github.com/choleraehyq/pid v0.0.13 -> v0.0.15 github.com/cloudwego/fastpb v0.0.2 github.com/jhump/protoreflect v1.8.2 - - - diff --git a/content/zh/blog/releases/Kitex/release-v043.md b/content/zh/blog/releases/Kitex/release-v043.md index af32ba4a73..e0811b4d09 100644 --- a/content/zh/blog/releases/Kitex/release-v043.md +++ b/content/zh/blog/releases/Kitex/release-v043.md @@ -5,6 +5,7 @@ projects: ["Kitex"] date: 2022-11-02 description: > --- + ## 重要变更介绍 ### 功能 @@ -19,61 +20,60 @@ description: > 1. **Frugal 性能优化** :支持在创建 Client/Server 阶段进行 Frugal “预编译”,减少动态编译对延迟的影响。 2. **连接池优化** :重构连接池,完善空闲连接清理能力。 ----- +--- ## 详细变更 ### Feature -* [[#691](https://github.com/cloudwego/kitex/pull/691)] feat(client): 为 Client 添加上下文中间件,用于请求粒度添加中间件。 -* [[#649](https://github.com/cloudwego/kitex/pull/649)] feat(connpool): 长连接池的新实现,支持最小空闲连接数及空闲连接清理。 -* [[#672](https://github.com/cloudwego/kitex/pull/672)] feat(grpc): 为 kitex grpc 添加了元信息传递相关 api,包括 header,tailer,以及 peer 远端地址的获取接口。 -* [[#613](https://github.com/cloudwego/kitex/pull/613)] feat(exception): 支持用户自定义异常用以区分 RPC 异常。 -* [[#670](https://github.com/cloudwego/kitex/pull/670)] feat(exception): 支持 DetailError 格式化。 -* [[#678](https://github.com/cloudwego/kitex/pull/678)] feat(tool): 为 kitex cmd 添加 git 和 record 参数。 -* [[#662](https://github.com/cloudwego/kitex/pull/662)] feat(tool): 支持在创建 client 或者 server 的时候进行 frugal “预编译” (pretouch)。 -* [[#657](https://github.com/cloudwego/kitex/pull/657)] feat(tool): 支持模板拓展。 -* [[#527](https://github.com/cloudwego/kitex/pull/527)] feat(profiler): 为不同的 RPC 请求提供成本分析统计的能力。 +- [[#691](https://github.com/cloudwego/kitex/pull/691)] feat(client): 为 Client 添加上下文中间件,用于请求粒度添加中间件。 +- [[#649](https://github.com/cloudwego/kitex/pull/649)] feat(connpool): 长连接池的新实现,支持最小空闲连接数及空闲连接清理。 +- [[#672](https://github.com/cloudwego/kitex/pull/672)] feat(grpc): 为 kitex grpc 添加了元信息传递相关 api,包括 header,tailer,以及 peer 远端地址的获取接口。 +- [[#613](https://github.com/cloudwego/kitex/pull/613)] feat(exception): 支持用户自定义异常用以区分 RPC 异常。 +- [[#670](https://github.com/cloudwego/kitex/pull/670)] feat(exception): 支持 DetailError 格式化。 +- [[#678](https://github.com/cloudwego/kitex/pull/678)] feat(tool): 为 kitex cmd 添加 git 和 record 参数。 +- [[#662](https://github.com/cloudwego/kitex/pull/662)] feat(tool): 支持在创建 client 或者 server 的时候进行 frugal “预编译” (pretouch)。 +- [[#657](https://github.com/cloudwego/kitex/pull/657)] feat(tool): 支持模板拓展。 +- [[#527](https://github.com/cloudwego/kitex/pull/527)] feat(profiler): 为不同的 RPC 请求提供成本分析统计的能力。 ### Optimize -* [[#690](https://github.com/cloudwego/kitex/pull/690)] optimize(meta): 移除 #503 添加 default metahandler 的错误逻辑。 -* [[#638](https://github.com/cloudwego/kitex/pull/638)] optimize(generic): httppb 泛化支持 map/list 元素类型为 struct。 -* [[#641](https://github.com/cloudwego/kitex/pull/641)] optimize(tool): 给 oneway 方法增加警告注释。 +- [[#690](https://github.com/cloudwego/kitex/pull/690)] optimize(meta): 移除 #503 添加 default metahandler 的错误逻辑。 +- [[#638](https://github.com/cloudwego/kitex/pull/638)] optimize(generic): httppb 泛化支持 map/list 元素类型为 struct。 +- [[#641](https://github.com/cloudwego/kitex/pull/641)] optimize(tool): 给 oneway 方法增加警告注释。 ### Fix -* [[#611](https://github.com/cloudwego/kitex/pull/611)] fix(client): 在频繁重复创建 Client 场景下,修复由于 finalizer 未触发执行导致的资源泄漏。 -* [[#698](https://github.com/cloudwego/kitex/pull/698)] fix(connpool): 根据 Get 返回的连接数减少值来调整 globalIdle。 -* [[#636](https://github.com/cloudwego/kitex/pull/636)] fix(connpool): 修复当连接池在 `ForwardProxy` 实现中被重置后,连接池的 CloseCallback、统计上报失效的问题。 -* [[#647](https://github.com/cloudwego/kitex/pull/647)] fix(grpc): 修复 grpc 连接级别窗口初始化时没有通知对端的问题,并同步了 grpc pr #5459。 -* [[#639](https://github.com/cloudwego/kitex/pull/639)] fix(generic): 泛化调用支持 list 类型,map 读泛化增加 forJSON 选项。 -* [[#655](https://github.com/cloudwego/kitex/pull/655)] fix(generic): 数值型常量作为泛化默认值时无法被正确解析。 -* [[#654](https://github.com/cloudwego/kitex/pull/654)] fix(frugal): 修复较低版本 go 编译失败的问题。 -* [[#682](https://github.com/cloudwego/kitex/pull/682)] fix(profiler): 修复 profiler 停止 pprof profile 采集的问题。 -* [[#637](https://github.com/cloudwego/kitex/pull/637)] fix(tool): 修复 handler.go 模板里的 imports。 -* [[#630](https://github.com/cloudwego/kitex/pull/630)] fix(tool): 对于没有声明 “service” 的 pb 文件,去掉生成文件末尾冗余的 kitex 声明。 -* [[#627](https://github.com/cloudwego/kitex/pull/627)] fix(tool): 修复当一个 import 拥有不同的别名时 import 会丢失的问题。 +- [[#611](https://github.com/cloudwego/kitex/pull/611)] fix(client): 在频繁重复创建 Client 场景下,修复由于 finalizer 未触发执行导致的资源泄漏。 +- [[#698](https://github.com/cloudwego/kitex/pull/698)] fix(connpool): 根据 Get 返回的连接数减少值来调整 globalIdle。 +- [[#636](https://github.com/cloudwego/kitex/pull/636)] fix(connpool): 修复当连接池在 `ForwardProxy` 实现中被重置后,连接池的 CloseCallback、统计上报失效的问题。 +- [[#647](https://github.com/cloudwego/kitex/pull/647)] fix(grpc): 修复 grpc 连接级别窗口初始化时没有通知对端的问题,并同步了 grpc pr #5459。 +- [[#639](https://github.com/cloudwego/kitex/pull/639)] fix(generic): 泛化调用支持 list 类型,map 读泛化增加 forJSON 选项。 +- [[#655](https://github.com/cloudwego/kitex/pull/655)] fix(generic): 数值型常量作为泛化默认值时无法被正确解析。 +- [[#654](https://github.com/cloudwego/kitex/pull/654)] fix(frugal): 修复较低版本 go 编译失败的问题。 +- [[#682](https://github.com/cloudwego/kitex/pull/682)] fix(profiler): 修复 profiler 停止 pprof profile 采集的问题。 +- [[#637](https://github.com/cloudwego/kitex/pull/637)] fix(tool): 修复 handler.go 模板里的 imports。 +- [[#630](https://github.com/cloudwego/kitex/pull/630)] fix(tool): 对于没有声明 “service” 的 pb 文件,去掉生成文件末尾冗余的 kitex 声明。 +- [[#627](https://github.com/cloudwego/kitex/pull/627)] fix(tool): 修复当一个 import 拥有不同的别名时 import 会丢失的问题。 ### Refactor -* [[#651](https://github.com/cloudwego/kitex/pull/651)] refactor(server): 重构 server trans handler 的 read/write 接口,返回新的 context。 +- [[#651](https://github.com/cloudwego/kitex/pull/651)] refactor(server): 重构 server trans handler 的 read/write 接口,返回新的 context。 ### Docs -* [[#656](https://github.com/cloudwego/kitex/pull/656)] docs: 删除 CONTRIBUTING 文档中的错误信息。 -* [[#683](https://github.com/cloudwego/kitex/pull/683)] docs(kerrors): 修改了 kerrors WithCauseAndExtraMsg 方法注释。 -* [[#625](https://github.com/cloudwego/kitex/pull/625)] chore: 修正 pull request 模板的语法问题。 -* [[#623](https://github.com/cloudwego/kitex/pull/623)] chore: 修改 pull request 模板。 +- [[#656](https://github.com/cloudwego/kitex/pull/656)] docs: 删除 CONTRIBUTING 文档中的错误信息。 +- [[#683](https://github.com/cloudwego/kitex/pull/683)] docs(kerrors): 修改了 kerrors WithCauseAndExtraMsg 方法注释。 +- [[#625](https://github.com/cloudwego/kitex/pull/625)] chore: 修正 pull request 模板的语法问题。 +- [[#623](https://github.com/cloudwego/kitex/pull/623)] chore: 修改 pull request 模板。 ### Test & CI -* [[#646](https://github.com/cloudwego/kitex/pull/646)] test: 修复 InitRPCInfoFunc 未设置 rpcinfo 导致的单测失败。 -* [[#680](https://github.com/cloudwego/kitex/pull/680)] test: 修复重试单测的 race 问题。 -* [[#661](https://github.com/cloudwego/kitex/pull/661)] test: 增强 wpool 测试稳定性。 -* [[#643](https://github.com/cloudwego/kitex/pull/643)] test: 为 detection server handler 添加测试。 -* [[#632](https://github.com/cloudwego/kitex/pull/632)] test: 用 gomock 自动生成类替换手动编写的 mock 类。 -* [[#697](https://github.com/cloudwego/kitex/pull/697)] chore(ci): 固定 skywalking-eyes 版本号。 -* [[#652](https://github.com/cloudwego/kitex/pull/652)] chore(ci): 删除重复的测试,以减少单测所花费的时间。 -* [[#588](https://github.com/cloudwego/kitex/pull/588)] chore(ci): 支持 codecov。 - +- [[#646](https://github.com/cloudwego/kitex/pull/646)] test: 修复 InitRPCInfoFunc 未设置 rpcinfo 导致的单测失败。 +- [[#680](https://github.com/cloudwego/kitex/pull/680)] test: 修复重试单测的 race 问题。 +- [[#661](https://github.com/cloudwego/kitex/pull/661)] test: 增强 wpool 测试稳定性。 +- [[#643](https://github.com/cloudwego/kitex/pull/643)] test: 为 detection server handler 添加测试。 +- [[#632](https://github.com/cloudwego/kitex/pull/632)] test: 用 gomock 自动生成类替换手动编写的 mock 类。 +- [[#697](https://github.com/cloudwego/kitex/pull/697)] chore(ci): 固定 skywalking-eyes 版本号。 +- [[#652](https://github.com/cloudwego/kitex/pull/652)] chore(ci): 删除重复的测试,以减少单测所花费的时间。 +- [[#588](https://github.com/cloudwego/kitex/pull/588)] chore(ci): 支持 codecov。 diff --git a/content/zh/blog/releases/Kitex/release-v050.md b/content/zh/blog/releases/Kitex/release-v050.md index ee810a8f9c..a68efd44a8 100644 --- a/content/zh/blog/releases/Kitex/release-v050.md +++ b/content/zh/blog/releases/Kitex/release-v050.md @@ -5,22 +5,24 @@ projects: ["Kitex"] date: 2023-03-08 description: > --- + ## 重要变更介绍 ### 功能 **1. Fallback 功能: 支持 Client 侧的 Fallback 功能** - 业务在 RPC 请求失败后通常会有一些降级措施保证有效返回(比如在请求超时、熔断后,构造默认返回),Kitex 的 Fallback 支持对所有异常请求进行处理。 - 同时,因为业务异常通常会通过 BaseResp 字段返回,所以也支持对 Resp 进行处理。详见 [Fallback](/zh/docs/kitex/tutorials/service-governance/fallback/)。 +业务在 RPC 请求失败后通常会有一些降级措施保证有效返回(比如在请求超时、熔断后,构造默认返回),Kitex 的 Fallback 支持对所有异常请求进行处理。 +同时,因为业务异常通常会通过 BaseResp 字段返回,所以也支持对 Resp 进行处理。详见 [Fallback](/zh/docs/kitex/tutorials/service-governance/fallback/)。 **2. Kitex - gRPC:Client 增加 TLS 的配置** - 通过 client.WithGRPCTLSConfig option 配置。 +通过 client.WithGRPCTLSConfig option 配置。 **3. Kitex - 工具** + - **支持自定义脚手架模板**,详见: [自定义脚手架模板](/zh/docs/kitex/tutorials/code-gen/custom_tpl/) -- **支持指定生成代码的目录**,详见: [代码生成工具 -gen-path](/zh/docs/kitex/tutorials/code-gen/code_generation/#-gen-path) +- **支持指定生成代码的目录**,详见: [代码生成工具 -gen-path](/zh/docs/kitex/tutorials/code-gen/code_generation/#-gen-path) - **支持 protoc 插件选项**,详见: [代码生成工具 -protobuf-plugin](/zh/docs/kitex/tutorials/code-gen/code_generation/#-protobuf-plugin) ### 优化 @@ -38,7 +40,7 @@ description: > 升级 frugal, pid 库依赖以支持 go 1.20。 ----- +--- ## 详细变更 @@ -57,7 +59,7 @@ description: > ### Optimize - [[#750](https://github.com/cloudwego/kitex/pull/750)] optimize(generic): generic call write zero value for required and default fields to meet the specification of apache thrift and keep consistent with normal thrift encode of Kitex. -- [[#739](https://github.com/cloudwego/kitex/pull/739)] optimize(generic): modify the url routing to align with Hertz for HTTP generic call +- [[#739](https://github.com/cloudwego/kitex/pull/739)] optimize(generic): modify the url routing to align with Hertz for HTTP generic call - [[#752](https://github.com/cloudwego/kitex/pull/752)] optimize(ttheader): attach part of ttheader binary into error when readKVInfo failed, which is useful for troubleshooting - [[#821](https://github.com/cloudwego/kitex/pull/821)] optimize(config): add DeepCopy() & Equals() to circuitbreaker.CBConfig and retry.Policy - [[#827](https://github.com/cloudwego/kitex/pull/827)] optimize: revise the remoteInfo of retry call, using the remoteInfo of the RPCCall that returns @@ -97,4 +99,3 @@ description: > - [[#761](https://github.com/cloudwego/kitex/pull/761)] docs: update README.md @fuergaosi233 - [[#817](https://github.com/cloudwego/kitex/pull/817), [#832](https://github.com/cloudwego/kitex/pull/832)] chore: upgrade dependency lib to adapt go 1.20 - [[#772](https://github.com/cloudwego/kitex/pull/772)] chore: modify kitex gen code meta file name from kitex.yaml to kitex_info.yaml - diff --git a/content/zh/blog/releases/Kitex/release-v052.md b/content/zh/blog/releases/Kitex/release-v052.md index 92743354da..d920ce5f12 100644 --- a/content/zh/blog/releases/Kitex/release-v052.md +++ b/content/zh/blog/releases/Kitex/release-v052.md @@ -5,6 +5,7 @@ projects: ["Kitex"] date: 2023-04-21 description: > --- + ## 重要变更介绍 ### 功能 @@ -14,40 +15,39 @@ description: > 3. 超时错误类型拆分:支持细粒度的超时错误类型,将 ErrRPCTimeout 细分为三个错误类型:超时、业务cancel、业务timeout。 4. Thrift FastCodec:支持 unknown fields。 - * unknown fields 使用背景:在 thrift 中,IDL 内增加字段对未更新 IDL 的一方是无感知的,必须更新 IDL 与生成代码以获取到新的字段。这会导致调用链路上某个节点更新 IDL 时,下游所有节点均需要进行更新。 - - * unknown fields 则支持保留未识别的字段,对于 IDL 内不存在的字段,读取并设置于结构体的 `_unknownFields` 字段。 + - unknown fields 使用背景:在 thrift 中,IDL 内增加字段对未更新 IDL 的一方是无感知的,必须更新 IDL 与生成代码以获取到新的字段。这会导致调用链路上某个节点更新 IDL 时,下游所有节点均需要进行更新。 - * 使用方法:`kitex -thrift keep_unknown_fields your.thrift` + - unknown fields 则支持保留未识别的字段,对于 IDL 内不存在的字段,读取并设置于结构体的 `_unknownFields` 字段。 + - 使用方法:`kitex -thrift keep_unknown_fields your.thrift` ### 修复 + 1. 失败重试策略:修复失败重试策略被动态修改后,结果重试 (resultRetry) 策略失效的问题。 ----- +--- ## 详细变更 -Feature: ---- -* [[#887](https://github.com/cloudwego/kitex/pull/887)] feat(retry): 增加配置,支持异常重试场景下不对超时做重试,用于请求非幂等的场景 -* [[#881](https://github.com/cloudwego/kitex/pull/881)] feat(tool): 支持 windows 场景下的代码生成 -* [[#880](https://github.com/cloudwego/kitex/pull/880)] feat(rpctimeout): 支持细粒度的超时错误类型 -* [[#872](https://github.com/cloudwego/kitex/pull/872)] feat(thrift): 在 fast codec 中支持 unknown fields 的序列化及反序列化 +## Feature: -Optimize: ---- -* [[#884](https://github.com/cloudwego/kitex/pull/884)] optimize(rpcinfo): RPCInfo.To().Tag() 优先使用服务发现的instance tag而不是remoteinfo tag +- [[#887](https://github.com/cloudwego/kitex/pull/887)] feat(retry): 增加配置,支持异常重试场景下不对超时做重试,用于请求非幂等的场景 +- [[#881](https://github.com/cloudwego/kitex/pull/881)] feat(tool): 支持 windows 场景下的代码生成 +- [[#880](https://github.com/cloudwego/kitex/pull/880)] feat(rpctimeout): 支持细粒度的超时错误类型 +- [[#872](https://github.com/cloudwego/kitex/pull/872)] feat(thrift): 在 fast codec 中支持 unknown fields 的序列化及反序列化 -Fix: ---- -* [[#896](https://github.com/cloudwego/kitex/pull/896)] fix(remoteinfo): 修复 remoteinfo 中非深拷贝的 CopyFrom 引入的 race 问题 -* [[#892](https://github.com/cloudwego/kitex/pull/892)] fix(grpc): 注释 ReadFrame error 时输出的 error 日志 -* [[#889](https://github.com/cloudwego/kitex/pull/889)] fix(retry): 在失败重试策略被动态修改后,结果重试策略失效 -* [[#866](https://github.com/cloudwego/kitex/pull/866)] fix(grpc): stream 的 sendMsg/recvMsg 返回的 ctx 无需赋值给 stream 的 ctx +## Optimize: -Chore: ---- -* [[#898](https://github.com/cloudwego/kitex/pull/898)] chore: 更新 PR 的模板,对用户文档的更新做 check -* [[#854](https://github.com/cloudwego/kitex/pull/854)] style(nphttp2): 保证 receiver 的名字一致 +- [[#884](https://github.com/cloudwego/kitex/pull/884)] optimize(rpcinfo): RPCInfo.To().Tag() 优先使用服务发现的instance tag而不是remoteinfo tag + +## Fix: + +- [[#896](https://github.com/cloudwego/kitex/pull/896)] fix(remoteinfo): 修复 remoteinfo 中非深拷贝的 CopyFrom 引入的 race 问题 +- [[#892](https://github.com/cloudwego/kitex/pull/892)] fix(grpc): 注释 ReadFrame error 时输出的 error 日志 +- [[#889](https://github.com/cloudwego/kitex/pull/889)] fix(retry): 在失败重试策略被动态修改后,结果重试策略失效 +- [[#866](https://github.com/cloudwego/kitex/pull/866)] fix(grpc): stream 的 sendMsg/recvMsg 返回的 ctx 无需赋值给 stream 的 ctx + +## Chore: +- [[#898](https://github.com/cloudwego/kitex/pull/898)] chore: 更新 PR 的模板,对用户文档的更新做 check +- [[#854](https://github.com/cloudwego/kitex/pull/854)] style(nphttp2): 保证 receiver 的名字一致 diff --git a/content/zh/blog/releases/Kitex/release-v060.md b/content/zh/blog/releases/Kitex/release-v060.md index 72bf3067cd..e245e90948 100644 --- a/content/zh/blog/releases/Kitex/release-v060.md +++ b/content/zh/blog/releases/Kitex/release-v060.md @@ -5,6 +5,7 @@ projects: ["Kitex"] date: 2023-06-14 description: > --- + ## 重要变更介绍 ### 功能 @@ -40,11 +41,12 @@ client 默认将 header 设置到 ctx,外部方法可利用 `GetHeaderMetadata 升级 netpoll 库依赖至 v0.4.0 ,同时支持 [configmanager](https://github.com/cloudwego/configmanager) v0.2.0 版本。 ----- +--- ## 详细变更 ## Feature: + - [[#923](https://github.com/cloudwego/kitex/pull/923)] feat(grpc): grpc 客户端将 header 和 trailer 设置到 context 内,并提供接口从 context 获取 header - [[#891](https://github.com/cloudwego/kitex/pull/891)] feat: 支持 rpc client 和 server 的服务合并,它可以将远端 rpc 调用改成本地的函数级调用。这个特性需要生成工具支持 - [[#946](https://github.com/cloudwego/kitex/pull/946)] feat: default server handler 支持通过trans pipeline执行Read函数 @@ -54,6 +56,7 @@ client 默认将 header 设置到 ctx,外部方法可利用 `GetHeaderMetadata - [[#897](https://github.com/cloudwego/kitex/pull/897)] feat: 自定义模板中支持 loop_service ## Optimize: + - [[#961](https://github.com/cloudwego/kitex/pull/961)] optimize(tool): -use 参数支持自定义模板场景 - [[#966](https://github.com/cloudwego/kitex/pull/966)] optimize(ttheader): ttheader 的 headerFlags 处理增加类型检查 - [[#919](https://github.com/cloudwego/kitex/pull/919)] optimize: 使用 GoFunc 替代 go func 以避免 panic @@ -63,6 +66,7 @@ client 默认将 header 设置到 ctx,外部方法可利用 `GetHeaderMetadata - [[#941](https://github.com/cloudwego/kitex/pull/941)] optimize(callopt): 优化 callopt 的 debug 信息,减少 slice 扩张的可能性 ## Fix: + - [[#963](https://github.com/cloudwego/kitex/pull/963)] fix(generic): 修复 map 泛化调用在 byte 类型字段 panic 的问题 - [[#901](https://github.com/cloudwego/kitex/pull/901)] fix(mux): 多路复用连接的 asynccallback 不创建新 goroutine,并且 server 等待所有 crrst 包都被 client 接收后再关闭 - [[#921](https://github.com/cloudwego/kitex/pull/921)] fix(loadbalance): 修复一致性 hash []byte 数组长度不够用的问题 @@ -70,14 +74,17 @@ client 默认将 header 设置到 ctx,外部方法可利用 `GetHeaderMetadata - [[#927](https://github.com/cloudwego/kitex/pull/927)] fix(connpool): 长连接池复用连接成功时进行上报 ## Refactor: + - [[#958](https://github.com/cloudwego/kitex/pull/958)] refactor(errorHandler): 重构 error handler 定义,可以获取更新信息处理 error - [[#943](https://github.com/cloudwego/kitex/pull/943)] refactor(client): 重构 client.Call 提升代码可读性 - [[#560](https://github.com/cloudwego/kitex/pull/560)] refactor: 重构server detection trans handler以支持多种协议的探测 ## Tests: + - [[#900](https://github.com/cloudwego/kitex/pull/900)] test(generic): 添加使用 dynamicgo 的 thrift 反射泛化调用示例 ## Chore: + - [[#976](https://github.com/cloudwego/kitex/pull/976)] chore: 更新 netpoll 版本到 v0.4.0 并且更新 thriftgo 版本到 v0.2.11 - [[#956](https://github.com/cloudwego/kitex/pull/956)] chore: 更新 configmanager 版本到 v0.2.0 - [[#948](https://github.com/cloudwego/kitex/pull/948)] chore: 使用 goimports -local github.com/cloudwego/kitex 调整仓库格式 diff --git a/content/zh/blog/releases/Kitex/release-v070.md b/content/zh/blog/releases/Kitex/release-v070.md index ec4ff0eb4c..29d772102d 100644 --- a/content/zh/blog/releases/Kitex/release-v070.md +++ b/content/zh/blog/releases/Kitex/release-v070.md @@ -5,6 +5,7 @@ projects: ["Kitex"] date: 2023-08-14 description: > --- + ## 重要变更介绍 ### 功能 @@ -31,12 +32,12 @@ description: > 升级 Thriftgo 库依赖至 v0.3.0 ,支持了 Thriftgo 反射功能,可以在运行时获取 IDL 元信息 - ----- +--- ## 详细变更 ### Feature: + - [[#1053](https://github.com/cloudwego/kitex/pull/1053)] feat(retry): support to distinguish local retry request - [[#1058](https://github.com/cloudwego/kitex/pull/1058)] feat(retry): support delete retry policy dynamically - [[#1000](https://github.com/cloudwego/kitex/pull/1000)] feat(grpc): support grpc compress @@ -47,6 +48,7 @@ description: > - [[#1019](https://github.com/cloudwego/kitex/pull/1019)] feat(lb): interleaved weighted round-robin load balancer ### Optimize: + - [[#1064](https://github.com/cloudwego/kitex/pull/1064)] optimize: check header max size when ttheader encode - [[#1017](https://github.com/cloudwego/kitex/pull/1017)] optimize: implement unknown field function without serialization - [[#1036](https://github.com/cloudwego/kitex/pull/1036)] optimize(protobuf): ignore err when (un)marshal empty req/resp @@ -56,6 +58,7 @@ description: > - [[#1020](https://github.com/cloudwego/kitex/pull/1020)] optimize: add nil check for MethodInfo which get from ServiceInfo in client.Call to ignore panic ### Fix: + - [[#1073](https://github.com/cloudwego/kitex/pull/1073)] fix: fix failure retryer dump panic - [[#1067](https://github.com/cloudwego/kitex/pull/1067)] fix: slim template with deepcopy - [[#1055](https://github.com/cloudwego/kitex/pull/1055)] fix: ignore SIGHUP when run with nohup @@ -70,6 +73,7 @@ description: > - [[#994](https://github.com/cloudwego/kitex/pull/994)] fix(tool): fix kitex tool git repo pulling logic ### Chore: + - [[#1074](https://github.com/cloudwego/kitex/pull/1074)] chore: update thriftgo to v0.3.0 - [[#1031](https://github.com/cloudwego/kitex/pull/1031)] chore: remove wechat group in readme - [[#1008](https://github.com/cloudwego/kitex/pull/1008)] chore: update dynamicgo to v0.1.1 diff --git a/content/zh/blog/releases/Kitex/release-v072.md b/content/zh/blog/releases/Kitex/release-v072.md index 1ff6f77d1f..374477cecd 100644 --- a/content/zh/blog/releases/Kitex/release-v072.md +++ b/content/zh/blog/releases/Kitex/release-v072.md @@ -5,6 +5,7 @@ projects: ["Kitex"] date: 2023-09-27 description: > --- + ## 重要变更介绍 ### 功能 @@ -18,7 +19,6 @@ description: > 1. 使用 `retry.NewRetryContainerWithPercentageLimit()` 来构造 RetryContainer,限制重试请求占比; 2. 在 Client 初始化时添加选项 `client.WithCloseCallbacks(container.Close)`,以便在 client 被回收时释放相关资源。 - ### 优化 **1. gRPC** @@ -30,25 +30,28 @@ description: > 如果没有指定 `MaxIdleGlobal` 则默认不限制,简化长连接池的使用配置。 - ### 其他 - 更新 netpoll 至 [v0.5.0](https://github.com/cloudwego/netpoll/releases/tag/v0.5.0) - 升级 frugal 到 [v0.1.8](https://github.com/cloudwego/frugal/releases/tag/v0.1.8),支持在 go1.21 编译时使用 frugal (注: frugal 旧版本不支持 go1.21) - ----- +--- ## 详细变更 ### Feature: + - [[#1117](https://github.com/cloudwego/kitex/pull/1117)] feat(retry): support retry percentage limit + ### Optimize: + - [[#1033](https://github.com/cloudwego/kitex/pull/1033)] optimize: no need to check svcInfo twice - [[#1115](https://github.com/cloudwego/kitex/pull/1115)] optimize: rm outdated framed suggestion - [[#1095](https://github.com/cloudwego/kitex/pull/1095)] optimize: add K_METHOD in serviceinline ctx - [[#1107](https://github.com/cloudwego/kitex/pull/1107)] optimize(connpool): set maxIdleGlobal to no limit if not set + ### Fix: + - [[#1116](https://github.com/cloudwego/kitex/pull/1116)] fix: use the last rpcinfo to trace - [[#1104](https://github.com/cloudwego/kitex/pull/1104)] fix: move limiter handler to the last of the inbound handler to get rpcinfo in custom limiter - [[#1103](https://github.com/cloudwego/kitex/pull/1103)] fix: reset all fields of netpoll byte buffer when recycle it @@ -58,15 +61,17 @@ description: > - [[#1098](https://github.com/cloudwego/kitex/pull/1098)] fix(tool): fix import for codegen template when using slim and unknown fields ### Tests: + - [[#1124](https://github.com/cloudwego/kitex/pull/1124)] test: fix codegen script - [[#1122](https://github.com/cloudwego/kitex/pull/1122)] test: add codegen test - [[#1119](https://github.com/cloudwego/kitex/pull/1119)] test(connpool): modify the idleTimeout ## Chore: + - [[#1133](https://github.com/cloudwego/kitex/pull/1133)] chore: update version v0.7.2 - [[#1125](https://github.com/cloudwego/kitex/pull/1125)] chore: upgrade netpoll to v0.5.0 - [[#1123](https://github.com/cloudwego/kitex/pull/1123)] perf: replace concurrent string builder with lock - [[#1118](https://github.com/cloudwego/kitex/pull/1118)] perf: optimize remote addr setter interface to reduce lock cost of Address() - [[#1110](https://github.com/cloudwego/kitex/pull/1110)] chore: upgrade netpoll to v0.4.2 pre-release - [[#1061](https://github.com/cloudwego/kitex/pull/1061)] chore: netpoll pre release v0.4.2 -- [[#1100](https://github.com/cloudwego/kitex/pull/1100)] chore: enable frugal on go1.21 \ No newline at end of file +- [[#1100](https://github.com/cloudwego/kitex/pull/1100)] chore: enable frugal on go1.21 diff --git a/content/zh/blog/releases/Kitex/release-v080.md b/content/zh/blog/releases/Kitex/release-v080.md index 2e253b3fd7..335e228dae 100644 --- a/content/zh/blog/releases/Kitex/release-v080.md +++ b/content/zh/blog/releases/Kitex/release-v080.md @@ -5,9 +5,11 @@ projects: ["Kitex"] date: 2023-11-30 description: > --- + ## **重要变更介绍** ### 功能 + **1. gRPC 协议支持多 Service** Kitex gRPC 支持多 Service 的能力,详见 [Multiple Services](/zh/docs/kitex/tutorials/advanced-feature/multi_service/). @@ -17,6 +19,7 @@ Kitex gRPC 支持多 Service 的能力,详见 [Multiple Services](/zh/docs/kit 提供 kitexutil 方法以方便从 RPCInfo 获取 rpc 信息, 详见 [Acquire RPC information](/zh/docs/kitex/tutorials/basic-feature/acquire_rpcinfo/). ### 优化 + **1. Map 泛化调用** Map 泛化支持通过 SetBinaryWithByteSlice 设置对 binary 字段返回 []byte。 @@ -25,18 +28,20 @@ Map 泛化支持通过 SetBinaryWithByteSlice 设置对 binary 字段返回 []by 允许关闭 RPCInfo 复用,简化异步使用方式,详见 [Acquire RPC information](/zh/docs/kitex/tutorials/basic-feature/acquire_rpcinfo/#12-异步使用方式). - ### 其它 升级 Frugal [v0.1.12](https://github.com/cloudwego/frugal/releases/tag/v0.1.12), 修复同时使用 frugal 和 sonic 时极小概率出现的并发问题。 强烈建议同时升级 frugal 和 sonic 到较新的版本。 - ```shell - go get github.com/cloudwego/frugal@latest - go get github.com/bytedance/sonic@latest - ``` + +```shell + go get github.com/cloudwego/frugal@latest + go get github.com/bytedance/sonic@latest +``` + ## **详细变更** ### Feature: + [[#1051](https://github.com/cloudwego/kitex/pull/1051)] feat(grpc): support gRPC multi-service on a server [[#1189](https://github.com/cloudwego/kitex/pull/1189)] feat(rpcinfo): add kitexutil methods for the convenience to fetch rpc information from RPCInfo [[#1176](https://github.com/cloudwego/kitex/pull/1176)] feat(tool): add an environment variable to make it easier to debug kitex tool @@ -44,22 +49,28 @@ Map 泛化支持通过 SetBinaryWithByteSlice 设置对 binary 字段返回 []by [[#1172](https://github.com/cloudwego/kitex/pull/1172)] feat(retry): client.WithSpecifiedResultRetry should have higher priority [[#1150](https://github.com/cloudwego/kitex/pull/1150)] feat(proxy): add an interface to customize proxy middleware to replace the default implementation [[#1159](https://github.com/cloudwego/kitex/pull/1159)] feat(generic): support returning []byte for binary fields in map generic -[[#1153](https://github.com/cloudwego/kitex/pull/1153)] feat(retry): add Extra for retry.FailurePolicy for better extension +[[#1153](https://github.com/cloudwego/kitex/pull/1153)] feat(retry): add Extra for retry.FailurePolicy for better extension + ### Optimize: + [[#1187](https://github.com/cloudwego/kitex/pull/1187)] optimize(tool): add an option to keep resp for kitex tool [[#1183](https://github.com/cloudwego/kitex/pull/1183)] optimize(meshheader): retrieve rip from meshheader and write it to TransInfo -[[#1178](https://github.com/cloudwego/kitex/pull/1178)] optimize(bizErr): recurse to obtain BizErr to avoid additional Error encapsulation in the middle, resulting in unwrap results that are not BizErr +[[#1178](https://github.com/cloudwego/kitex/pull/1178)] optimize(bizErr): recurse to obtain BizErr to avoid additional Error encapsulation in the middle, resulting in unwrap results that are not BizErr + ### Fix: + [[#1126](https://github.com/cloudwego/kitex/pull/1126)] fix(generic): the issue of structs cache of generic call has dirty data under multiple services scene [[#1168](https://github.com/cloudwego/kitex/pull/1168)] fix(tool): remove the pointer to java.Object in generated file for [CodecDubbo](https://github.com/kitex-contrib/codec-dubbo) [[#1169](https://github.com/cloudwego/kitex/pull/1169)] fix(tool): empty struct generate wrong struct [[#1166](https://github.com/cloudwego/kitex/pull/1166)] fix(generic): issue of deep copy function generation when map key type is binary -[[#1155](https://github.com/cloudwego/kitex/pull/1155)] fix(tool): add import package 'context' for gRPC client.go +[[#1155](https://github.com/cloudwego/kitex/pull/1155)] fix(tool): add import package 'context' for gRPC client.go ### Tests: -[[#1177](https://github.com/cloudwego/kitex/pull/1177)] test: avoid port conflict + +[[#1177](https://github.com/cloudwego/kitex/pull/1177)] test: avoid port conflict ### Chore: + [[#1190](https://github.com/cloudwego/kitex/pull/1190)] chore: update thriftgo version to v0.3.3 [[#1186](https://github.com/cloudwego/kitex/pull/1186)] chore: update readme with examples and new blogs [[#1185](https://github.com/cloudwego/kitex/pull/1185)] chore: add ci for windows @@ -68,4 +79,4 @@ Map 泛化支持通过 SetBinaryWithByteSlice 设置对 binary 字段返回 []by [[#1164](https://github.com/cloudwego/kitex/pull/1164)] chore: update frugal to v0.1.12 and allow disable frugal by build tag [[#1161](https://github.com/cloudwego/kitex/pull/1161)] chore: update frugal to v0.1.10 [[#1157](https://github.com/cloudwego/kitex/pull/1157)] chore: update frugal to v0.1.9 -[[#1151](https://github.com/cloudwego/kitex/pull/1151)] chore(test): upgrade mockey to latest to compatible with Go1.21 +[[#1151](https://github.com/cloudwego/kitex/pull/1151)] chore(test): upgrade mockey to latest to compatible with Go1.21 diff --git a/content/zh/blog/releases/Kitex/release-v090.md b/content/zh/blog/releases/Kitex/release-v090.md index e8e154b4eb..02efbb09e7 100644 --- a/content/zh/blog/releases/Kitex/release-v090.md +++ b/content/zh/blog/releases/Kitex/release-v090.md @@ -13,6 +13,7 @@ v0.9.0 针对 Thrift 提供了两个重要的功能:Thrift Streaming 和 Multi ## **重要变更介绍** ### 功能 + **1. Thrift Streaming** 基于 gRPC(HTTP2) 的 Thrift Streaming 功能正式 Release,用户可以使用 Thrift IDL 定义自己的 Streaming 请求,为保持 IDL 解析的兼容性,Kitex 的 Streaming 方法的定义通过注解的方式,使用方式见 [Thrift Streaming Usage](/zh/docs/kitex/tutorials/basic-feature/protocol/transport-streaming/thrift_streaming/)。本版本也对 Streaming 请求的监控上报做了改进,同样适用于 gRPC-Protobuf。注意,Thrift 主要用于结构体序列化,并没有使用 Thrift 消息协议。 @@ -45,8 +46,6 @@ v0.9.0 针对 Thrift 提供了两个重要的功能:Thrift Streaming 和 Multi 新增 Alias Method 的负载均衡方法,来减少权重随机负载均衡算法的时间复杂度。通过 `client.WithLoadBalancer(loadbalance.NewWeightedRandomWithAliasMethodBalancer())` 指定。 - - ### 特别的变更 v0.9.0 要求 Go 版本必须 >= 1.17,不再兼容 Go <= v1.16 (稳定性要求必须升级 golang.org/x/ 库引入的 Go 版本限制) @@ -62,6 +61,7 @@ Kitex 对超时、重试、熔断、限流的策略支持通过远程配置中 ## **详细变更** ### Feature: + 1. [[#1208](https://github.com/cloudwego/kitex/pull/1208), [#1251](https://github.com/cloudwego/kitex/pull/1251), [#1230](https://github.com/cloudwego/kitex/pull/1230), [#1226](https://github.com/cloudwego/kitex/pull/1226)] feat: support thrift streaming (replacing the protobuf payload of GRPC/HTTP2 with thrift binary) 2. [[#1217](https://github.com/cloudwego/kitex/pull/1217)] feat: support thrift and pb multi service 3. [[#1268](https://github.com/cloudwego/kitex/pull/1268)] feat(thrift): support frugal fallback for arm @@ -74,6 +74,7 @@ Kitex 对超时、重试、熔断、限流的策略支持通过远程配置中 10. [[#1211](https://github.com/cloudwego/kitex/pull/1211)] feat(hessian2): support nested struct for hessian2 customized Exception ### Optimize: + 1. [[#1222](https://github.com/cloudwego/kitex/pull/1222)] optimize(frugal): enable frugal by default when the generated code is using slim template 2. [[#1209](https://github.com/cloudwego/kitex/pull/1209)] optimize: split encoder interface to customize meta and payload encoding implementation 3. [[#1206](https://github.com/cloudwego/kitex/pull/1206)] optimize(tool): add IsDir judge in readTemplate and add template register func @@ -84,6 +85,7 @@ Kitex 对超时、重试、熔断、限流的策略支持通过远程配置中 8. [[#1238](https://github.com/cloudwego/kitex/pull/1238)] optimize(bizerr): support biz status error for streaming mode ### Fix: + 1. [[#1236](https://github.com/cloudwego/kitex/pull/1236)] fix(hessian2): correct code-ref behavior when thrift file is not in project dir 2. [[#1234](https://github.com/cloudwego/kitex/pull/1234)] fix(hessian2): still perform replacement on handler.go when -service is not specified for hessian2 3. [[#1232](https://github.com/cloudwego/kitex/pull/1232)] fix(gRPC): append "h2" to next proto in gRPC tlsConfig to enable protocol negotiation in TLS @@ -93,6 +95,7 @@ Kitex 对超时、重试、熔断、限流的策略支持通过远程配置中 7. [[#1194](https://github.com/cloudwego/kitex/pull/1194)] fix(retry): always set RespOp && preventive panic to avoid dead loop ### Chore & Tests + 1. [[#1273](https://github.com/cloudwego/kitex/pull/1273)] chore: upgrade netpoll to v0.6.0 2. [[#1263](https://github.com/cloudwego/kitex/pull/1263)] chore: update sonic to v1.11.1 3. [[#1255](https://github.com/cloudwego/kitex/pull/1255)] chore: upgrade netpoll to v0.6.0 pre-release version @@ -102,6 +105,7 @@ Kitex 对超时、重试、熔断、限流的策略支持通过远程配置中 7. [[#1220](https://github.com/cloudwego/kitex/pull/1220)] test: correct the cachekey in the benchmark test of balancer 8. [[#1196](https://github.com/cloudwego/kitex/pull/1196)] test: add just biz handler message error ------- +--- + **Thanks a lot to those community contributors who submit some pull requests or share your ideas for this version:** -@DMwangnima @jizhuozhi @NX-Official @jieqiboh @Lvnszn @Skyenought +@DMwangnima @jizhuozhi @NX-Official @jieqiboh @Lvnszn @Skyenought diff --git a/content/zh/blog/releases/Volo/_index.md b/content/zh/blog/releases/Volo/_index.md index f63f18d104..cdfa04f70d 100644 --- a/content/zh/blog/releases/Volo/_index.md +++ b/content/zh/blog/releases/Volo/_index.md @@ -4,4 +4,3 @@ linkTitle: "Volo" projects: ["Volo"] weight: 4 --- - diff --git a/content/zh/blog/releases/Volo/release-v0100.md b/content/zh/blog/releases/Volo/release-v0100.md index 3ebf1f44cf..685cdbe33d 100644 --- a/content/zh/blog/releases/Volo/release-v0100.md +++ b/content/zh/blog/releases/Volo/release-v0100.md @@ -1,6 +1,6 @@ --- -title: 'Volo 0.10.0 版本发布' -linkTitle: 'Release v0.10.0' +title: "Volo 0.10.0 版本发布" +linkTitle: "Release v0.10.0" projects: ["Volo"] date: 2024-04-08 description: > @@ -59,7 +59,6 @@ let x = xxx().map_err(|e|anyhow::anyhow!(e))?; client 部分的错误从原来的 `ResponseError` 改为了 `ClientError`,按编译器报错提示匹配新的错误 variant 即可。 - ### IDL 管理文件 volo.yml 格式重构 新版 yml 配置的结构更加清晰,且更易于维护,并主要解决了旧版中无法支持 git 跨仓库引用的问题,具体的功能和配置参数见 [config](https://www.cloudwego.io/zh/docs/volo/guide/config)。另外,对于 volo-cli 命令行工具,我们将之前的 idl 命令名字修改为了 repo。 @@ -68,7 +67,6 @@ client 部分的错误从原来的 `ResponseError` 改为了 `ClientError`,按 安装 volo-cli 0.10.0 版本,并在 volo.yml 目录下执行 volo migrate 命令即可自动迁移。 - ### 默认生成的 Enum 类型修改 在新版生成代码中,默认生成的 Enum 类型修改为了 i32 wrapper 的 newtype 类型,以便于更好的向前兼容 IDL enum 字段中枚举值的修改。 @@ -77,7 +75,6 @@ client 部分的错误从原来的 `ResponseError` 改为了 `ClientError`,按 将 enum 字段中枚举值名字修改为对应生成的名字即可,如 `Foo::Bar` -> `Foo::BAR`。 - ## 完整 Release Note 完整的 Release Note 可以参考:[Volo Changelog](https://github.com/cloudwego/volo/compare/volo-0.9.0...volo-0.10.0) diff --git a/content/zh/blog/releases/Volo/release-v020.md b/content/zh/blog/releases/Volo/release-v020.md index 77ee372991..9499cc7767 100644 --- a/content/zh/blog/releases/Volo/release-v020.md +++ b/content/zh/blog/releases/Volo/release-v020.md @@ -8,20 +8,19 @@ description: > ## Feature -* [[#31](https://github.com/cloudwego/volo/pull/31)] 支持 Windows。 -* [[#26](https://github.com/cloudwego/volo/pull/26)] volo-grpc 增加对 service discovery 和 load balance 的支持。 -* [[#45](https://github.com/cloudwego/volo/pull/45)] volo-grpc 支持 uds。 -* [[#32](https://github.com/cloudwego/volo/pull/32)] volo-grpc 支持 metainfo 进行元信息传递。 -* [[#30](https://github.com/cloudwego/volo/pull/30)] volo-grpc Server 增加 `layer_front` 方法。 -* [[#42](https://github.com/cloudwego/volo/pull/42)] volo-thrift 支持 multiplex。 +- [[#31](https://github.com/cloudwego/volo/pull/31)] 支持 Windows。 +- [[#26](https://github.com/cloudwego/volo/pull/26)] volo-grpc 增加对 service discovery 和 load balance 的支持。 +- [[#45](https://github.com/cloudwego/volo/pull/45)] volo-grpc 支持 uds。 +- [[#32](https://github.com/cloudwego/volo/pull/32)] volo-grpc 支持 metainfo 进行元信息传递。 +- [[#30](https://github.com/cloudwego/volo/pull/30)] volo-grpc Server 增加 `layer_front` 方法。 +- [[#42](https://github.com/cloudwego/volo/pull/42)] volo-thrift 支持 multiplex。 ## Optimize -* [[#53](https://github.com/cloudwego/volo/pull/53)] 优化 `write_field_begin` 函数。 +- [[#53](https://github.com/cloudwego/volo/pull/53)] 优化 `write_field_begin` 函数。 ## Fix -* [[#34](https://github.com/cloudwego/volo/pull/34)] 修复连接超时设置。 -* [[#46](https://github.com/cloudwego/volo/pull/46)] 增加对可重试错误的判断。 -* [[#33](https://github.com/cloudwego/volo/pull/33)] volo-grpc 修复对 Error 类型的约束。 - +- [[#34](https://github.com/cloudwego/volo/pull/34)] 修复连接超时设置。 +- [[#46](https://github.com/cloudwego/volo/pull/46)] 增加对可重试错误的判断。 +- [[#33](https://github.com/cloudwego/volo/pull/33)] volo-grpc 修复对 Error 类型的约束。 diff --git a/content/zh/blog/releases/Volo/release-v021.md b/content/zh/blog/releases/Volo/release-v021.md index 2672fdb166..c9582f7437 100644 --- a/content/zh/blog/releases/Volo/release-v021.md +++ b/content/zh/blog/releases/Volo/release-v021.md @@ -6,9 +6,8 @@ date: 2022-10-26 description: > --- -* [[#61](https://github.com/cloudwego/volo/pull/61)] 优化了 Volo-Thrift 的代码,移除了一些不必要的泛型参数,简化代码。 -* [[#63](https://github.com/cloudwego/volo/pull/63)] 跟进了 2022-10-20 后 nightly 编译器不再允许 TAIT elition lifetime 的问题。 -* [[#73](https://github.com/cloudwego/volo/pull/73)] 绕过了 Rust 编译器的 #100013 issue: non-defining opaque type use in defining scope。 -* [[#65](https://github.com/cloudwego/volo/pull/65)] feat: 升级 Volo-cli 的 clap 版本到 4.x。 -* [[#72](https://github.com/cloudwego/volo/pull/72)] feat: 为 volo::net::Conn 支持了 writev 操作。 - +- [[#61](https://github.com/cloudwego/volo/pull/61)] 优化了 Volo-Thrift 的代码,移除了一些不必要的泛型参数,简化代码。 +- [[#63](https://github.com/cloudwego/volo/pull/63)] 跟进了 2022-10-20 后 nightly 编译器不再允许 TAIT elition lifetime 的问题。 +- [[#73](https://github.com/cloudwego/volo/pull/73)] 绕过了 Rust 编译器的 #100013 issue: non-defining opaque type use in defining scope。 +- [[#65](https://github.com/cloudwego/volo/pull/65)] feat: 升级 Volo-cli 的 clap 版本到 4.x。 +- [[#72](https://github.com/cloudwego/volo/pull/72)] feat: 为 volo::net::Conn 支持了 writev 操作。 diff --git a/content/zh/blog/releases/Volo/release-v041.md b/content/zh/blog/releases/Volo/release-v041.md index 2362b44605..bb28791776 100644 --- a/content/zh/blog/releases/Volo/release-v041.md +++ b/content/zh/blog/releases/Volo/release-v041.md @@ -1,6 +1,6 @@ --- -title: 'Volo 0.4.1 版本发布' -linkTitle: 'Release v0.4.1' +title: "Volo 0.4.1 版本发布" +linkTitle: "Release v0.4.1" projects: ["Volo"] date: 2023-03-20 description: > diff --git a/content/zh/blog/releases/Volo/release-v050.md b/content/zh/blog/releases/Volo/release-v050.md index d4c0586533..71cc3fea2d 100644 --- a/content/zh/blog/releases/Volo/release-v050.md +++ b/content/zh/blog/releases/Volo/release-v050.md @@ -1,6 +1,6 @@ --- -title: 'Volo 0.5.0 版本发布' -linkTitle: 'Release v0.5.0' +title: "Volo 0.5.0 版本发布" +linkTitle: "Release v0.5.0" projects: ["Volo"] date: 2023-06-02 description: > diff --git a/content/zh/blog/releases/Volo/release-v054.md b/content/zh/blog/releases/Volo/release-v054.md index d24282142a..194db23587 100644 --- a/content/zh/blog/releases/Volo/release-v054.md +++ b/content/zh/blog/releases/Volo/release-v054.md @@ -1,6 +1,6 @@ --- -title: 'Volo 0.5.4 版本发布' -linkTitle: 'Release v0.5.4' +title: "Volo 0.5.4 版本发布" +linkTitle: "Release v0.5.4" projects: ["Volo"] date: 2023-08-28 description: > @@ -16,9 +16,9 @@ Volo 0.5.4 版本中,除了常规 bugfix 之外,还有一些新的 feature ### Solution -1. 在解码 read 步骤时,对于未识别的字段递归进行skip得到长度后,将对应长度的一段 bytes 直接存入生成的 _unknown_fields 结构中,省去具体类型的反序列化开销(在 volo 实现中这一块默认是 zerocopy 的实现)。如果是提前把已知字段读完,会直接把剩余 bytes 全存起来,从而不再需要递归解析长度,性能更优。 +1. 在解码 read 步骤时,对于未识别的字段递归进行skip得到长度后,将对应长度的一段 bytes 直接存入生成的 \_unknown_fields 结构中,省去具体类型的反序列化开销(在 volo 实现中这一块默认是 zerocopy 的实现)。如果是提前把已知字段读完,会直接把剩余 bytes 全存起来,从而不再需要递归解析长度,性能更优。 -2. 在编码 write 步骤时,直接将 _unknown_fields 整块 bytes 写入,省去序列化的开销(在 volo 实现中这一块是 zerocopy 的实现)。 +2. 在编码 write 步骤时,直接将 \_unknown_fields 整块 bytes 写入,省去序列化的开销(在 volo 实现中这一块是 zerocopy 的实现)。 ```thrift struct Test { @@ -49,7 +49,7 @@ pub Enum Hello { ### How To -在 volo.yml 中对要生成 _unknown_fields 的 thrift 文件进行配置。 +在 volo.yml 中对要生成 \_unknown_fields 的 thrift 文件进行配置。 ```yaml entries: @@ -70,7 +70,7 @@ entries: ### Solution -1. Thrift Binary Protocol Scalar Types 是定长编码,比如 i32 编码 4 Bytes ,那么 map/list/set 和定长类型组成的这些复合类型(Compound Types)就可以特殊处理,比如 list,按之前的 Skip 算法是 O(n) 操作循环 Skip,可以提前计算总长度直接跳过,算法复杂度变成了 O(1); +1. Thrift Binary Protocol Scalar Types 是定长编码,比如 i32 编码 4 Bytes ,那么 map/list/set 和定长类型组成的这些复合类型(Compound Types)就可以特殊处理,比如 list,按之前的 Skip 算法是 O(n) 操作循环 Skip,可以提前计算总长度直接跳过,算法复杂度变成了 O(1); 2. 使用循环替换递归; @@ -99,7 +99,7 @@ Found 10 outliers among 100 measurements (10.00%) 5 (5.00%) high severe ``` -## Hot Restart +## Hot Restart ### Motivation @@ -121,11 +121,11 @@ Found 10 outliers among 100 measurements (10.00%) 1. 要使用热重启,需要初始化热重启机制。 -2. 该进程首先尝试连接到 parent_sock。如果连接失败,则说明该进程是原来的父进程。这种情况下,进程应该绑定 parent_sock 和 parent_handle,等待子进程发送消息。 +2. 该进程首先尝试连接到 parent_sock。如果连接失败,则说明该进程是原来的父进程。这种情况下,进程应该绑定 parent_sock 和 parent_handle,等待子进程发送消息。 -3. 如果子进程成功连接到 parent_sock,它将使用 dup_parent_listener_sock 复制文件描述符。 +3. 如果子进程成功连接到 parent_sock,它将使用 dup_parent_listener_sock 复制文件描述符。 -4. 一旦所有监听器套接字都被复制,子进程就会向父进程发送终止父进程请求,父进程收到请求后启动终止信号(kill sigterm)并走gracefully exit流程完全退出进程。 +4. 一旦所有监听器套接字都被复制,子进程就会向父进程发送终止父进程请求,父进程收到请求后启动终止信号(kill sigterm)并走gracefully exit流程完全退出进程。 ### How To @@ -156,9 +156,9 @@ async fn main() { 2. initialize 方法两个参数: - 1. sock_dir_path: 存储 hot_restart 使用的UDS监听地址父目录,一般由托管进程分配地址,注意隔离性(尤其是物理机等非隔离环境下运行使用); + 1. sock_dir_path: 存储 hot_restart 使用的UDS监听地址父目录,一般由托管进程分配地址,注意隔离性(尤其是物理机等非隔离环境下运行使用); - 2. server_listener_num: 总共server监听数量,指启动的基于volo的server listener数量,一般服务只有一个server,比如Volo-Thrift Server,设置1即可; + 2. server_listener_num: 总共server监听数量,指启动的基于volo的server listener数量,一般服务只有一个server,比如Volo-Thrift Server,设置1即可; ## 完整 Release Note diff --git a/content/zh/blog/releases/Volo/release-v080.md b/content/zh/blog/releases/Volo/release-v080.md index 6f9c3c5d10..0b9eeb35d2 100644 --- a/content/zh/blog/releases/Volo/release-v080.md +++ b/content/zh/blog/releases/Volo/release-v080.md @@ -1,6 +1,6 @@ --- -title: 'Volo 0.8.0 版本发布' -linkTitle: 'Release v0.8.0' +title: "Volo 0.8.0 版本发布" +linkTitle: "Release v0.8.0" projects: ["Volo"] date: 2023-10-23 description: > @@ -90,6 +90,7 @@ pub trait Service { 1. Rust 编译器更新到最新 nightly(rustup update)及所有依赖(volo、pilota、motore)升级到最新版 2. cargo check 看看哪里报错,可能会遇到比如`type Future is not a member`、`associated type Future not found`等类似错误,我们以如下`Service`为例: + ```rust impl Service for LogService where @@ -117,10 +118,12 @@ where } } ``` + 3. 把`type Future`这行直接去掉 4. 把`fn call<'cx, 's>`中的生命周期位置对调,并去掉下面的`where`语句 5. 在`fn call`前面加个`async`,然后把`Self::Future<'cx>`这部分,改成`Result`,并去掉函数体里面的`async move` 6. 最终改完的`Service`如下: + ```rust impl Service for LogService where diff --git a/content/zh/blog/releases/Volo/release-v090.md b/content/zh/blog/releases/Volo/release-v090.md index e64aad2925..421fa71497 100644 --- a/content/zh/blog/releases/Volo/release-v090.md +++ b/content/zh/blog/releases/Volo/release-v090.md @@ -1,6 +1,6 @@ --- -title: 'Volo 0.9.0 版本发布' -linkTitle: 'Release v0.9.0' +title: "Volo 0.9.0 版本发布" +linkTitle: "Release v0.9.0" projects: ["Volo"] date: 2024-01-04 description: > @@ -30,7 +30,6 @@ volo-thrift client 中的 max_frame_size 由于迭代中接口变更,并没有 hyper 在 1.0 版本中移除了 hyper::Body,并引入了 hyper::body::Incoming 用作请求的 Body 类型。在 volo-grpc 中,我们跟进了这一改动,预计对绝大多数没有自己写 layer 的用户无感。如果有使用到完整 Service 泛型的用户,将 `Service>` 修改为 `Service>` 即可。 - ## 完整 Release Note 完整的 Release Note 可以参考:[Volo Changelog](https://github.com/cloudwego/volo/compare/volo-0.8.0...volo-0.9.0) diff --git a/content/zh/blog/releases/_index.md b/content/zh/blog/releases/_index.md index ceec0de5fa..e72c7ba1a8 100644 --- a/content/zh/blog/releases/_index.md +++ b/content/zh/blog/releases/_index.md @@ -1,9 +1,6 @@ - --- title: "发布" projects: [] linkTitle: "发布" weight: 2 --- - - diff --git a/content/zh/community/meeting_notes/2022-02-25/_index.md b/content/zh/community/meeting_notes/2022-02-25/_index.md index daa254646c..e275dfc5c0 100644 --- a/content/zh/community/meeting_notes/2022-02-25/_index.md +++ b/content/zh/community/meeting_notes/2022-02-25/_index.md @@ -1,6 +1,6 @@ --- title: CloudWeGo 社区会议 2.25 -linkTitle: CloudWeGo 社区会议 2.25 +linkTitle: CloudWeGo 社区会议 2.25 date: 2022-02-25 weight: 1 description: > @@ -11,12 +11,14 @@ description: > **参会人员:** Joway, YangruiEmma, liu-song, AshleeT, li-jin-gou, Hchenn, PureWhiteWu, GuangmingLuo, baiyutang, yccpt, horizonzy. **会前必读:** [官网](/); - https://github.com/cloudwego +https://github.com/cloudwego ## 议程 1 :自我介绍+历史贡献介绍 + 内容:参会人员轮流开展了自我介绍,包含个人基本情况、历史贡献、个人未来规划、相关建议。 ## 议程 2 :社区规划介绍和后续安排 + 社区介绍(@罗广明 负责介绍): 1. 对CloudWeGo官网进行了简要介绍,并欢迎社区成员对官网内容进行提问,发表看法。 @@ -25,6 +27,7 @@ description: > 4. 介绍 kitex 框架的扩展性,可支持很多能力的扩展,提出未来框架能和更多开源项目做一些对接。 Action Items + - 在官网 Community 部分,后期计划征得大家同意之后,公开各位Contributor 的信息,比如 GitHub 的一些 ID 头像。 - 在渠道推广方面,后期会考虑与社区其他开源项目合作与对接,包括框架接入、宣传推广等方面。 - 在 Kitex 框架对接方面,安排 Kitex 框架后期与更多的开源项目(有一定的用户量和知名度的开源项目)进行对接。 diff --git a/content/zh/community/meeting_notes/2022-03-11/_index.md b/content/zh/community/meeting_notes/2022-03-11/_index.md index b26a2eb4eb..f8e54e3d44 100644 --- a/content/zh/community/meeting_notes/2022-03-11/_index.md +++ b/content/zh/community/meeting_notes/2022-03-11/_index.md @@ -11,7 +11,7 @@ description: > **参会人员:** CoderPoet, liu-song, GuangmingLuo, Zheming Li, YangruiEmma, li-jin-gou, simon0-o, Dianjun Suo, jasondeng1997, lvnszn, baiyutang, Duslia, joway, Xuewu Jiang, AshleeT, yccpt. **会前必读:** [官网](/); - https://github.com/cloudwego +https://github.com/cloudwego ## 议程 1 :新人自我介绍 @@ -20,7 +20,7 @@ description: > ## 议程 2 :CloudWeGo 仓库介绍 1. 对 CloudWeGo 主仓库进行了简要介绍,欢迎社区成员对仓库进行补充加强。例如:欢迎大家在 Kitex_examples 仓库提交一些 Business demo,例如电商、医疗等不同行业场景下的典型案例 。 -2. Community 仓库:首先,Community 仓库刚成立不久,主要用于归档社区相关的材料,包括双周会的会议纪要(meeting_notes)和周报(weekly_report)。其次,也欢迎大家成为该仓库的正式成员,后续的活动可以第一时间通知到大家,便于大家参与到核心功能的讨论与开发。 +2. Community 仓库:首先,Community 仓库刚成立不久,主要用于归档社区相关的材料,包括双周会的会议纪要(meeting_notes)和周报(weekly_report)。其次,也欢迎大家成为该仓库的正式成员,后续的活动可以第一时间通知到大家,便于大家参与到核心功能的讨论与开发。 3. Kitex-contrib 仓库:该仓库包含了各种扩展的对接实现,比如对接 Prometheus,对接Opentracing 等。其中,OpenTelemetry 对接项目正处于提交 PR 的状态,欢迎大家参与到项目的共建和 review。 ## 议程 3:社区后续工作介绍 @@ -34,22 +34,26 @@ description: > **事项介绍** 1. 性能优化 - - Kitex-gRPC Streaming 性能提升。 - - Protobuf 编解码性能优化,初步完成,完善边界 case 。 - - Frugal - 无生成代码的高性能动态 Thrift编解码库。 + +- Kitex-gRPC Streaming 性能提升。 +- Protobuf 编解码性能优化,初步完成,完善边界 case 。 +- Frugal - 无生成代码的高性能动态 Thrift编解码库。 2. 新特性支持 - - Thrift 泛化调用 新增对 Protobuf 的支持用于网关 - - Protobuf <-> Thrift 高性能的协议转换 - - 重试:支持用户自定义异常重试 - - Proxyless 支持:完成服务发现/路由对 xds 接口扩展 + +- Thrift 泛化调用 新增对 Protobuf 的支持用于网关 +- Protobuf <-> Thrift 高性能的协议转换 +- 重试:支持用户自定义异常重试 +- Proxyless 支持:完成服务发现/路由对 xds 接口扩展 3. 功能优化: - - 重写连接池逻辑,支持更加优雅的空闲连接清理 - - 增加字段 Size 校验 + +- 重写连接池逻辑,支持更加优雅的空闲连接清理 +- 增加字段 Size 校验 4. 外部需求 - - 连接预热、连接多路复用通知上游退出 + +- 连接预热、连接多路复用通知上游退出 **Action Items** @@ -57,18 +61,17 @@ description: > **补充单元测试原则** - 1. 补充的单测必须是有意义的,验证某个逻辑的正确性,或者异常表现是否符合预期。 - - 2. 杜绝为了覆盖率而补全单测,宁可不加。 +1. 补充的单测必须是有意义的,验证某个逻辑的正确性,或者异常表现是否符合预期。 - 3. 每个单测必须要有断言。 +2. 杜绝为了覆盖率而补全单测,宁可不加。 - 4. 可以添加 mock 辅助单测。 +3. 每个单测必须要有断言。 - 5. 建议单测通过注释明确验证的逻辑。 +4. 可以添加 mock 辅助单测。 - 6. 不要在单测代码里用 printf 等手段打日志人肉去检验。 +5. 建议单测通过注释明确验证的逻辑。 +6. 不要在单测代码里用 printf 等手段打日志人肉去检验。 ## 议程 5:Q&A @@ -76,7 +79,6 @@ description: > A:Kitex 支持 Thrift streaming 我们刚开始是计划要做的,但是之后了解到目前没有应用场景,没有用户提出需要用到 Thrift Streaming, 因此,这个计划我们就搁置了。如果没有收到真实的业务场景需求,我们暂时不去安排这个功能支持。 - **Q:Proxyless 支持这块是一个 doing 状态吗?** A:之前是有一个同学在跟进,但是后来因为内部有其它事情处理就没有再继续做了。如果你感兴趣的话,可以加入进来一起支持。 diff --git a/content/zh/community/meeting_notes/2022-03-25/_index.md b/content/zh/community/meeting_notes/2022-03-25/_index.md index 235c58a02b..543b82ea90 100644 --- a/content/zh/community/meeting_notes/2022-03-25/_index.md +++ b/content/zh/community/meeting_notes/2022-03-25/_index.md @@ -11,7 +11,7 @@ description: > **参会人员:** YangruiEmma, liu-song, baiyutang, yccpt, AshleeT, Authorixy, Dianjun Suo, bodhisatan, CoderPoet, Quan Hu, li-jin-gou, JZK-Keven, EastHorse, GuangmingLuo, Xiwen Li, joway, jasondeng1997, HeyJavaBean. **会前必读:** [官网](/); - https://github.com/cloudwego +https://github.com/cloudwego ## 议程 1 :新成员自我介绍 @@ -28,11 +28,12 @@ description: > b. Kitex 单测任务的 PR 的描述前缀统一使用 Test,便于相关同学进行 review。 c. 提交了 PR之后,可以将 PR 发送在群里,方便后续跟进。 + 4. **提交 PR 时间要求:** 认领之后半个月内提交 PR,便于后续的意见修改和调试。 ## 议程 3:源码分析落地 -1. **参考案例:** 具体可以参考 Go-zero 和 Kratos 开源社区。例如:对框架一些较好的设计进行解读,提供“扩展阅读”文档,目录可以涵盖“日志组件介绍”、“令牌桶限流”等文档内容。 +1. **参考案例:** 具体可以参考 Go-zero 和 Kratos 开源社区。例如:对框架一些较好的设计进行解读,提供“扩展阅读”文档,目录可以涵盖“日志组件介绍”、“令牌桶限流”等文档内容。 2. **后续规划:** a. 草拟源码分析目录大纲:① 目录结构和内容可以参考 CloudWeGo 官网目录;② 源码分析目录文档完成后,可以发在群里或者在 Github 上提交 Issue ,方便大家讨论修改;③ 认领单测任务的同学可以关注一下源码分析活动,助于更好地了解模块的功能。 @@ -48,4 +49,3 @@ A:确实存在循坏依赖的情况。对于这种情况,可以使用 mock ## 议程5:社区建议 欢迎大家将参与社区建设期间遇到的任何问题和想法发在群里,同社区成员一起沟通。内容不限于 Kitex、Netpoll 代码库、CloudWeGo 官网、宣传渠道等。 - diff --git a/content/zh/community/meeting_notes/2022-04-08/_index.md b/content/zh/community/meeting_notes/2022-04-08/_index.md index 5f85903a4d..f79de538eb 100644 --- a/content/zh/community/meeting_notes/2022-04-08/_index.md +++ b/content/zh/community/meeting_notes/2022-04-08/_index.md @@ -11,7 +11,7 @@ description: > **参会人员:** YangruiEmma, liu-song, yccpt, AshleeT, GuangmingLuo, CoderPoet, HeyJavaBean, jayantxie, JZK-Keven, Xiwen Li, joway, bodhisatan **会前必读:** [官网](/); - https://github.com/cloudwego +https://github.com/cloudwego ## 议程 1 :新成员自我介绍 @@ -19,18 +19,18 @@ description: > ## 议程 2 :Kitex 单测任务进展介绍 -* 没有提交 PR 的同学可以尽早提交 PR,便于后续相关同学进行 review。 -* 后期会为大家邮寄礼品。 +- 没有提交 PR 的同学可以尽早提交 PR,便于后续相关同学进行 review。 +- 后期会为大家邮寄礼品。 ## 议程 3 :Kitex 4月发版计划 -* 发版时间:**4 月 28 日**,发布中版本。 -* **4 月 20 日前**,各变更需完成独立的功能验证和性能测试;如无特殊情况, **4 月 22 日前**,完成所有变更合并,然后进入整体的功能验证和性能测试阶段。 +- 发版时间:**4 月 28 日**,发布中版本。 +- **4 月 20 日前**,各变更需完成独立的功能验证和性能测试;如无特殊情况, **4 月 22 日前**,完成所有变更合并,然后进入整体的功能验证和性能测试阶段。 ## 议程 4 :Q&A **Q:社区后续工作规划有哪些?** A:可以参考前期的会议纪要:https://github.com/cloudwego/community/tree/main/meeting_notes , - 以及 Kitex 的 RoadMap: https://github.com/cloudwego/kitex/blob/develop/ROADMAP.md 。 - 其它的规划还包括:1. 推进 xDS 的对接实现; 2. Kitex 对接支持业界开源服务治理能力和云平台。 +以及 Kitex 的 RoadMap: https://github.com/cloudwego/kitex/blob/develop/ROADMAP.md 。 +其它的规划还包括:1. 推进 xDS 的对接实现; 2. Kitex 对接支持业界开源服务治理能力和云平台。 diff --git a/content/zh/community/meeting_notes/2022-04-21/_index.md b/content/zh/community/meeting_notes/2022-04-21/_index.md index ab0cae0875..71509fe0bb 100644 --- a/content/zh/community/meeting_notes/2022-04-21/_index.md +++ b/content/zh/community/meeting_notes/2022-04-21/_index.md @@ -1,6 +1,6 @@ --- title: CloudWeGo 社区会议 4.21 -linkTitle: CloudWeGo 社区会议 4.21 +linkTitle: CloudWeGo 社区会议 4.21 date: 2022-04-21 weight: 5 description: > @@ -11,7 +11,7 @@ description: > **参会人员:** YangruiEmma, liu-song, baiyutang, yccpt, AshleeT, CoderPoet, Quan Hu, li-jin-gou, JZK-Keven, EastHorse, GuangmingLuo, HeyJavaBean, jayantxie, ppzqh, Shizheng Hou, andrewshan, simon0-o, yiyun, Wanqi Su, Zheming Li, Xianjie Yao, LoveScotty. **会前必读:** [官网](/); - https://github.com/cloudwego +https://github.com/cloudwego ## 议程 1 :新成员自我介绍 @@ -28,7 +28,7 @@ description: > b. 提交 PR 前:完成本地 Coding 后,**运行**`gofumpt -l -extra -w .`,检测代码是否存在语法、 License等问题。Contributor 在本地 Fix 这些问题后,能够顺利通过 CI 流程检测,顺利进入 review 环节。 - c. 提交 PR 时:若 PR 处于 Working In Progress 状态,大家在提交 PR 时可以选择 **Draft PR **,或者在 PR 描述中**加入 ****WIP**** 标识**,便于 Reviewer 优先处理完成状态的 PR。 + c. 提交 PR 时:若 PR 处于 Working In Progress 状态,大家在提交 PR 时可以选择 **Draft PR **,或者在 PR 描述中**加入 \*\***WIP\***\* 标识**,便于 Reviewer 优先处理完成状态的 PR。 d. 单测描述:需要在描述部分清晰、详细说明单测方法的**场景**,便于后续快速、准确地 Review 代码逻辑。 @@ -50,7 +50,7 @@ description: > ## 议程 4:Kitex 与阿里云 Nacos + Trace 对接工作进展介绍与讨论 -(@li-jin-gou 负责介绍) +(@li-jin-gou 负责介绍) 1. **背景介绍:** 我们希望将 [Demo(Easy-Note) ](https://github.com/cloudwego/kitex-examples/pull/27)部署到阿里云,主要的工作是验证 Kitex 接入阿里云的 ARMS 的链路追踪 和 MSE 的 Nacos 注册中心。 @@ -78,7 +78,7 @@ description: > **Q:我们是否也要把对接阿里云的相关基础设施统一放在一个 Suite 里面?** -A:目前还没有对接服务治理,我们的规划是:第一阶段支持注册中心和可观测系统的接入。比如,对Nacos 注册中心这块做了一些无侵入式配置的扩展对接,然后我们通过 OpenTelemetry 去接入阿里云的可观测系统;第二阶段,我们准备通过 Middleware 或 Suite 的方式对接开放服务治理的能力。现阶段的工作主要是对 Kitex 的 [Nacos registry](https://github.com/kitex-contrib/registry-nacos) 展开了优化,然后结合 OpenTelemetry 这一扩展,去重构 Kitex Easy-Note Demo。 +A:目前还没有对接服务治理,我们的规划是:第一阶段支持注册中心和可观测系统的接入。比如,对Nacos 注册中心这块做了一些无侵入式配置的扩展对接,然后我们通过 OpenTelemetry 去接入阿里云的可观测系统;第二阶段,我们准备通过 Middleware 或 Suite 的方式对接开放服务治理的能力。现阶段的工作主要是对 Kitex 的 [Nacos registry](https://github.com/kitex-contrib/registry-nacos) 展开了优化,然后结合 OpenTelemetry 这一扩展,去重构 Kitex Easy-Note Demo。 **Q:单测每次 CI 都会出报告吗?上次想加到 awesome go ,但是他们对覆盖度有要求。** @@ -87,4 +87,3 @@ A:可以点进 CI 的 Show all checks 查看测试报告,同时,在[单测 ## 相关资讯 截至 4 月 21 日,历时 5 个月,**CloudWeGo-Kitex** 完成了 3000 Stars 到 **4000 Stars** 的跨越,来到新的里程碑! - diff --git a/content/zh/community/meeting_notes/2022-05-19/_index.md b/content/zh/community/meeting_notes/2022-05-19/_index.md index 082f3f8bd7..2722dd848a 100644 --- a/content/zh/community/meeting_notes/2022-05-19/_index.md +++ b/content/zh/community/meeting_notes/2022-05-19/_index.md @@ -11,7 +11,7 @@ description: > **参会人:** YangruiEmma, ag9920, Jiang Xuewu, liu-song, Joway, yccpt, Huang Yuting, CoderPoet, li-jin-gou, GuangmingLuo, simon0-o, scotty, yiyun, Authorixy, JZK-Keven, bodhisatan, ppzqh, Jacob953, Ivnszn, cyyolo, debug-LiXiwen, baize **会前必读:** [官网](/) - https://github.com/cloudwego +https://github.com/cloudwego **录屏链接:** https://bytedance.feishu.cn/minutes/obcn3zdn1g46avv887i11ms9?from=from_copylink @@ -19,22 +19,24 @@ description: > 1. 介绍新的开源项目 Frugal,欢迎感兴趣的同学熟悉并参与此项目。Kitex 下一个版本正式支持 Frugal,Kitex 新版本发布之后正式对外发文分享与宣传 Frugal。 2. Hertz 预计会在 5 月底或者 6 月初正式对外开源。正式开源后会发布会发布新手任务(代码层面 + 文档翻译),欢迎大家踊跃参与。 + --- ### 议程 2 :Kitex 单测任务进展梳理 @GuangmingLuo 1. **完成进度:7/14** -2. **提交 ****PR**** 注意事项:** +2. **提交 \*\***PR\***\* 注意事项:** 1. 一定注意 CI 报错,及时修复错误; 2. 遵守 Issue Description 提到的要求; 3. 提交 PR 的同学加快进度,团队内部负责 Review 的同学加紧跟进。争取在 5 月份的下一个版本发布之前,可以合入这些 PR。 4. 需要 Rebase 的 Develop 代码单测错误已得到修复,Rebase 一下 Develop 分支代码即可解决。 + 3. 因疫情影响,目前居家办公,给所有贡献者邮寄礼物进程会推迟,复工后统一邮寄。请同学们不用过于担心,承诺的礼物一定送到。 --- -### 议程 3:Kitex 对接 xDS 方案介绍 @ppzqh @CoderPoet +### 议程 3:Kitex 对接 xDS 方案介绍 @ppzqh @CoderPoet 1. 相关文档:[Kitex 对接 xDS 总体技术方案设计](https://bytedance.feishu.cn/docx/doxcnQMRyKL6OcOg0lFR7W3PQIg?from=from_copylink) 2. 提炼功能,在 Kitex 上面提一个 Issue,对要做的 Feature 做背景和方案概述,拆分开发工作量,方便社区里面感兴趣的同学参加。 @@ -81,4 +83,3 @@ description: > 新的开源项目 Frugal 已经 Public,欢迎大家熟悉了解并积极参与。 地址:https://github.com/cloudwego/frugal。 - diff --git a/content/zh/community/meeting_notes/2022-06-02/_index.md b/content/zh/community/meeting_notes/2022-06-02/_index.md index 3276bf0d8a..f620ae1311 100644 --- a/content/zh/community/meeting_notes/2022-06-02/_index.md +++ b/content/zh/community/meeting_notes/2022-06-02/_index.md @@ -28,11 +28,11 @@ description: > ### 议程 3:Integrate Polaris Go SDK to Support Their Service Governance Ability 任务介绍 @jayantxie 1. 地址:https://github.com/cloudwego/kitex/issues/421 - 已认领 Issue @debug-LiXiwen -3. 继注册发现能力之后,再以 Polaris 为服务治理中心,集成服务治理能力。熔断部分会在 Kitex 中注入 Middleware,通过 Middleware 上报每次请求结果。上报时需要 Polaris 实例,所以需要转换一下,这个转换可以通过缓存用 Key 去做查找。 -4. 此 PR 已经支持外部限流器的实现。可以通过扩展接口传入外部实现的限流器,对接 Polaris 的限流功能。 -5. 关于动态路由和负载均衡,通过扩展 Kitex LoadBalancer 实现。在 Polaris LoadBalancer 里,通过服务发现的实例去构造 Kitex 的实例,在LoadBalancer 接口里把这个实例转换成 Polaris 的实例,再把它写到缓存里。每一次 Pick 时,从 Pick 里找到调用 Polaris 动态路由的 API 对应的子集,再从这些子集里调用负载均衡的 API ,拿到对应实例。这个实例需要转成 Kitex 的 Instance, 所以也需要通过 Key 做查找操作。扩展 Next Picker 只会在第一次选择时执行这个逻辑。 -6. 新建 Polaris 仓库,把原有 Registry-Polaris 仓库代码复制过去,后续只维持新仓库。 + 已认领 Issue @debug-LiXiwen +2. 继注册发现能力之后,再以 Polaris 为服务治理中心,集成服务治理能力。熔断部分会在 Kitex 中注入 Middleware,通过 Middleware 上报每次请求结果。上报时需要 Polaris 实例,所以需要转换一下,这个转换可以通过缓存用 Key 去做查找。 +3. 此 PR 已经支持外部限流器的实现。可以通过扩展接口传入外部实现的限流器,对接 Polaris 的限流功能。 +4. 关于动态路由和负载均衡,通过扩展 Kitex LoadBalancer 实现。在 Polaris LoadBalancer 里,通过服务发现的实例去构造 Kitex 的实例,在LoadBalancer 接口里把这个实例转换成 Polaris 的实例,再把它写到缓存里。每一次 Pick 时,从 Pick 里找到调用 Polaris 动态路由的 API 对应的子集,再从这些子集里调用负载均衡的 API ,拿到对应实例。这个实例需要转成 Kitex 的 Instance, 所以也需要通过 Key 做查找操作。扩展 Next Picker 只会在第一次选择时执行这个逻辑。 +5. 新建 Polaris 仓库,把原有 Registry-Polaris 仓库代码复制过去,后续只维持新仓库。 --- @@ -54,4 +54,3 @@ description: > **Kitex** v0.3.2 已发布! [https://github.com/cloudwego/kitex/releases/tag/v0.3.2](https://github.com/cloudwego/kitex/releases/tag/v0.3.2) - diff --git a/content/zh/community/meeting_notes/2022-06-16/_index.md b/content/zh/community/meeting_notes/2022-06-16/_index.md index aea26e423e..2216cdd1d2 100644 --- a/content/zh/community/meeting_notes/2022-06-16/_index.md +++ b/content/zh/community/meeting_notes/2022-06-16/_index.md @@ -18,18 +18,18 @@ description: > 2. **项目背景:** Hertz 之前,字节跳动内部使用的 HTTP 框架是基于 Gin 进行了一层封装。存在的问题:Gin 出现 Bug 无法修复;难以迭代支持一些 Feature;随着业务发展性能不足逐渐显现,且难以改变。 3. **Hertz 定位 :** -* 超大规模企业级实现,拥有极强的稳定性。 -* 微服务框架。完善 CloudWeGo 的生态矩阵,让 CloudWeGo 成为云原生最佳的解决方案之一,从而向客户推广。 -* 开箱即用的框架。包括比如搭积木的能力,用户可以按需组装模块;可能会生成一些 Client 代码,可以方便用户 Benchmark 或者帮助用户去调试,甚至生成一些生产上的代码。 -* “三高”的框架。高扩展性、高易用性和高性能。 +- 超大规模企业级实现,拥有极强的稳定性。 +- 微服务框架。完善 CloudWeGo 的生态矩阵,让 CloudWeGo 成为云原生最佳的解决方案之一,从而向客户推广。 +- 开箱即用的框架。包括比如搭积木的能力,用户可以按需组装模块;可能会生成一些 Client 代码,可以方便用户 Benchmark 或者帮助用户去调试,甚至生成一些生产上的代码。 +- “三高”的框架。高扩展性、高易用性和高性能。 4. **内部使用情况:** 是内部最大的 HTTP 框架,在内部线上有 1w+ 的服务峰值,QPS 4000w+。某些典型服务迁移 Hertz 后,相比 Gin 框架,CPU 使用率降低 30%—60%。 5. **Roadmap:** -* 无缝接入微服务体系。支持 xDS API,从 Istio 动态获取服务配置。 -* 有更完善的生态。如 CORS、Trace、Metrics 、反向代理、Session 等。 -* 支持多协议。Hertz 目前只开源了 HTTP1 的部分,未来还会开源其他协议,如:HTTP2、Websocket、ALPN 等。 -* 更高的性能。结合用户需求,持续迭代。 +- 无缝接入微服务体系。支持 xDS API,从 Istio 动态获取服务配置。 +- 有更完善的生态。如 CORS、Trace、Metrics 、反向代理、Session 等。 +- 支持多协议。Hertz 目前只开源了 HTTP1 的部分,未来还会开源其他协议,如:HTTP2、Websocket、ALPN 等。 +- 更高的性能。结合用户需求,持续迭代。 6. **6.21** 官宣后会开放新手任务,以及社区参与指南,欢迎大家参与 Hertz 社区贡献。 @@ -39,7 +39,7 @@ description: > 1. 项目地址:https://github.com/hertz-contrib/swagger;https://github.com/hertz-contrib/jwt 2. 贡献了 Hertz 的两个插件,Swagger 和 JWT。Fork 了 Gin 排名比较高的对应的仓库,然后对赫兹做适配,争取让开发者比较方便的从 Gin 切换到 Hertz。过程中需要看一些赫兹的接口源码,保证 Hertz 和 Gin 的表现相同。 -3. 对 Hertz 源码感兴趣的初学者可以从这里入手,建议社区也可以考虑把一些 Gin 里面常见的中间件以 First-good-issue 的形式开放。 +3. 对 Hertz 源码感兴趣的初学者可以从这里入手,建议社区也可以考虑把一些 Gin 里面常见的中间件以 First-good-issue 的形式开放。 --- @@ -78,4 +78,3 @@ description: > 6 月 25 日,CloudWeGo & 稀土掘金 Meetup 活动直播,邀请到来自字节跳动、森马电商和华兴证券的资深开发者,向社区分享 CloudWeGo 的最新企业落地实践。 活动链接:https://mp.weixin.qq.com/s/D93dk-9dw2pQocI4anBXfg - diff --git a/content/zh/community/meeting_notes/2022-06-30/_index.md b/content/zh/community/meeting_notes/2022-06-30/_index.md index 9f5a2d6bf0..ee756658bf 100644 --- a/content/zh/community/meeting_notes/2022-06-30/_index.md +++ b/content/zh/community/meeting_notes/2022-06-30/_index.md @@ -24,8 +24,8 @@ description: > 1. Kitex 单测任务还有两个子任务待完成,希望加快进度。后续会持续放出其它新手任务,希望大家可以保持关注并积极参与。后续针对 PR 可能会有单测覆盖率限制,希望后面每一个提交贡献的同学都能补充相关的单测,提升相关模块的单测覆盖率,保证项目的代码质量。 2. Hertz 文档建设进展: -* 先前发布了文档翻译类型的新手任务,英文文档建设是项目非常重要的一部分,新手、字节内部同学、国内熟悉英文的用户都可查看。后续也会将项目进行国际化推广,因而英文文档建设也是很有价值的。 -* 英文文档建设可以锻炼英文翻译能力、对项目技术的理解能力,在翻译时要考虑中英文表达方式的差异,不能只是文字对照翻译。也欢迎大家后续对文档翻译进行持续优化,这也是为社区作出重要贡献的方式之一。 +- 先前发布了文档翻译类型的新手任务,英文文档建设是项目非常重要的一部分,新手、字节内部同学、国内熟悉英文的用户都可查看。后续也会将项目进行国际化推广,因而英文文档建设也是很有价值的。 +- 英文文档建设可以锻炼英文翻译能力、对项目技术的理解能力,在翻译时要考虑中英文表达方式的差异,不能只是文字对照翻译。也欢迎大家后续对文档翻译进行持续优化,这也是为社区作出重要贡献的方式之一。 --- @@ -35,8 +35,8 @@ description: > 2. **背景**:用户在做技术选型的时候,对工具化模板是有一定诉求的,比如说怎样快速便捷生成一些基础的业务代码。对比 Go-zero 框架的 API 生成、RPC 生成、Model 生成以及模版的管理四类命令工具,Kitex 有一些生成客户端代码的命令、生成基础 Handler 方法的服务端代码命令等,如果想满足更多用户的诉求,我们可以确定一个 Layout 或者丰富工具化、生成业务代码方面的命令。 3. **相关讨论**: -* Kitex 和 Hertz 有两套单独的 RPC 命令生成工具,生成 Model 可能需要一个总的工具,因为有很多业务诉求是有共性的,这个问题正在考虑中。 -* **Q**:Kitex 和 Hertz 同属一个 Group,命令是否可以相似,如果不去自动指定 Model 的话,可以自动从执行命令最近的文件夹里面找到 Go mod 文件? +- Kitex 和 Hertz 有两套单独的 RPC 命令生成工具,生成 Model 可能需要一个总的工具,因为有很多业务诉求是有共性的,这个问题正在考虑中。 +- **Q**:Kitex 和 Hertz 同属一个 Group,命令是否可以相似,如果不去自动指定 Model 的话,可以自动从执行命令最近的文件夹里面找到 Go mod 文件? **A**:建议提出 PR,相关同学后续会跟进。 欢迎感兴趣的同学加入讨论! @@ -47,20 +47,20 @@ description: > 1. Hertz 上周已正式官宣,内部在逐步梳理开源侧的 Roadmap。**主库拆成 Hertz 对外提供的各维度的能力:** -* HTTP2 在内部已经有一个工程实践,内部很多组件用户已经在使用,但是出于成熟度的考量,还没有正式开源。因此首先后期会补充 HTTP2 的能力,对此感兴趣的同学可以一起参与; -* HTTP3 的 RFC 文档在 6 月份正式发布,这部分也是即将举办的 Byte Camp 的议题,后续的开发工作也会以 Issue 和 PR 的形式直接在主库上展开。也欢迎大家加入到开发过程中; -* 关于协议,如 ALPN 已经开源,后续希望组织好这些协议,把 ALPN 的能力发挥到极致。协议间无感切换是说在用户在使用 Hertz 时,它能够做到一键切换协议版本; -* Automatic TLS 在内部不是刚需,主要面对开源用户。其余各维度的能力也在陆续梳理中。 -* 对于 Hz,后续会提供多场景、高定制化、开箱即用等用户自定义能力,通过 Hz 能够直接一键创建出可以快速上线的一整个代码脚架。还会涉及 API 管理以及生成工具提供一些更高层面的抽象能力,包括屏蔽掉 HTTP 协议相关的 Request Response,给用户生成一些基于 IDL、类似于 RPC 方向的开发体验。欢迎感兴趣的同学一起进行 Hz 工具的打磨。 +- HTTP2 在内部已经有一个工程实践,内部很多组件用户已经在使用,但是出于成熟度的考量,还没有正式开源。因此首先后期会补充 HTTP2 的能力,对此感兴趣的同学可以一起参与; +- HTTP3 的 RFC 文档在 6 月份正式发布,这部分也是即将举办的 Byte Camp 的议题,后续的开发工作也会以 Issue 和 PR 的形式直接在主库上展开。也欢迎大家加入到开发过程中; +- 关于协议,如 ALPN 已经开源,后续希望组织好这些协议,把 ALPN 的能力发挥到极致。协议间无感切换是说在用户在使用 Hertz 时,它能够做到一键切换协议版本; +- Automatic TLS 在内部不是刚需,主要面对开源用户。其余各维度的能力也在陆续梳理中。 +- 对于 Hz,后续会提供多场景、高定制化、开箱即用等用户自定义能力,通过 Hz 能够直接一键创建出可以快速上线的一整个代码脚架。还会涉及 API 管理以及生成工具提供一些更高层面的抽象能力,包括屏蔽掉 HTTP 协议相关的 Request Response,给用户生成一些基于 IDL、类似于 RPC 方向的开发体验。欢迎感兴趣的同学一起进行 Hz 工具的打磨。 -2. **Contrib 仓库为 ****Hertz**** 提供全方位的组件能力:** +2. **Contrib 仓库为 \*\***Hertz\***\* 提供全方位的组件能力:** -* Websocket 已经在内部使用一年多,本质上是基于 Gorilla Websocket 的库做适配,因此没有直接开源。后续可作为新手任务。 -* 反向代理与 Websocket 类似,这个实现也是基于 Golang 原生的实现做的适配,没有直接开源。后续可作为新手任务。 -* 常用中间件(Session/Compress/Cache),每个中间件相对独立,所以希望每个同学单独承接,做独立开发。 -* 服务治理相关能力,与 Automatic TLS 类似,在内部会直接卸载到 Service Mesh 上。服务发现、负载均衡、限流、熔断、超时,都在 Service Mesh上有对应的实现。这一系列的服务治理的相关能力也在开源的 Roadmap 中,后续会逐步地将任务梳理出来。 -* 可观测性(Log/Trace/Metrics),我们现在已经做了一些集成的,日志能够支持具体实现注入,Trace 也有相应的埋点,Example 库也提供了类似于使用 Tracing 能力的示例,这些也在规划中。 -* 云原生(Proxyless/一键部署/CICD),Proxyless 在服务治理能力补齐之后会开始做,直接对接 Istio,Kitex 的这部分已经在进行中,Hertz 后续也会逐步补充。一键部署是指部署到第三方云环境的能力,包括集成 CICD 等等,都是 Contrib 仓库会涵盖的。 +- Websocket 已经在内部使用一年多,本质上是基于 Gorilla Websocket 的库做适配,因此没有直接开源。后续可作为新手任务。 +- 反向代理与 Websocket 类似,这个实现也是基于 Golang 原生的实现做的适配,没有直接开源。后续可作为新手任务。 +- 常用中间件(Session/Compress/Cache),每个中间件相对独立,所以希望每个同学单独承接,做独立开发。 +- 服务治理相关能力,与 Automatic TLS 类似,在内部会直接卸载到 Service Mesh 上。服务发现、负载均衡、限流、熔断、超时,都在 Service Mesh上有对应的实现。这一系列的服务治理的相关能力也在开源的 Roadmap 中,后续会逐步地将任务梳理出来。 +- 可观测性(Log/Trace/Metrics),我们现在已经做了一些集成的,日志能够支持具体实现注入,Trace 也有相应的埋点,Example 库也提供了类似于使用 Tracing 能力的示例,这些也在规划中。 +- 云原生(Proxyless/一键部署/CICD),Proxyless 在服务治理能力补齐之后会开始做,直接对接 Istio,Kitex 的这部分已经在进行中,Hertz 后续也会逐步补充。一键部署是指部署到第三方云环境的能力,包括集成 CICD 等等,都是 Contrib 仓库会涵盖的。 希望已经给 Hertz 提供 PR 或 Issue 的同学多使用,帮助框架进一步做性能提升。细节部分可以在 Hertz SIG 讨论,公共事务可以在开发者交流群进行沟通。 @@ -89,6 +89,3 @@ A:Thrift 和 PB 都只是在 Hertz 中发挥接口描述的功能。除此之 **Q:因为 Hertz 和 Kitex 字节内部已经有一些应用实践经验,我们可以不仅仅从产品设计上去考虑,而且还要把它当做技术产品去看待,响应市场的需求。针对不同的人群来讲,第一类是不太了解微服务的概念或者实践的人群,第二类是更关注性能测试的中高级的用户,Hertz 和 Kitex 是否可以给出一些最佳实践文档?** **A:** 我们最近也开展了类似的源码解读活动,是面向新手和年轻开发者的活动,之后也在陆续整理一些相关概念和知识介绍。至于偏具体业务场景的使用案例,后续我们希望能有更多同学参与进来。这个其实是一个社区攻坚的过程,我们也会尽可能把字节内部已有的比较好的实践进行输出。希望大家能够就是借着这个框架可以自己去做一些相关领域的实践,我们目前也正在搭一个电商的样例,这个项目会在近期完成,最后我们会把它发布出来放在官网。一些企业用户案例也比较有借鉴意义,我们也希望能够在不同行业,比如电商、证券、游戏和机器学习等做一些企业用户的行业标杆。后续我们也会收集和整理相关企业用户进行落地页实现的案例,放在官网统一的位置做展示,让用户和需要做技术选型的同学能够快速地看到,能够了解这个项目究竟能给业务带来什么价值,能在哪些场景上铺开使用。 - - - diff --git a/content/zh/community/meeting_notes/2022-07-14/_index.md b/content/zh/community/meeting_notes/2022-07-14/_index.md index 1e956f60a7..77b5ca34e1 100644 --- a/content/zh/community/meeting_notes/2022-07-14/_index.md +++ b/content/zh/community/meeting_notes/2022-07-14/_index.md @@ -25,8 +25,8 @@ Fan Guangyu, Jacob953, Wang Yafeng, gova, Huang Xiaolong, Zhang Guiyuan, chenzBi 1. 介绍PPT:[过载保护-限流算法.pptx](https://bytedance.feishu.cn/file/boxcnfVCs9Nh6JxfqDkVG2MqyrQ?from=from_copylink) 2. 相关讨论: -* **Q:** 造成 CPU 负载的因素很多,如何判断这是通过访问量或者高并发请求产生的负载?有时用户的加码程序或者某些在系统上跑的程序也会导致 CPU 负载很高,会不会有限流失误的问题? -* **A:** 如果一个程序出现了问题,CPU 已经负载很高的时候,也没有必要再承担一个请求,因为这个机器的性能已经达到了负荷。 +- **Q:** 造成 CPU 负载的因素很多,如何判断这是通过访问量或者高并发请求产生的负载?有时用户的加码程序或者某些在系统上跑的程序也会导致 CPU 负载很高,会不会有限流失误的问题? +- **A:** 如果一个程序出现了问题,CPU 已经负载很高的时候,也没有必要再承担一个请求,因为这个机器的性能已经达到了负荷。 3. 后续补充限流算法相关案例和使用算法的趋势图,方便直观感受使用这个组件带来的收益。 @@ -36,34 +36,34 @@ Fan Guangyu, Jacob953, Wang Yafeng, gova, Huang Xiaolong, Zhang Guiyuan, chenzBi 1. 地址:github.com/hertz-contrib/obs-opentelemetry -* 默认提供开箱即用 OpenTelemetry Provider; -* 对 Hertz 做了一些 Instrumentation,主要有三点: - - * Tracing - * Support server and client Hertz http tracing - * Support automatic transparent transmission of peer service through http headers // 基于对端服务信息透传,实现服务拓扑能力 - * Metrics - * Support Hertz http metrics [R.E.D] // 做 http metrics 的埋点,实现一些服务的黄金指标 - * Support service topology map metrics [Service Topology Map] // 基于 http headers 透传对端服务信息,生成 Service Topology Map - * Support go runtime metrics - * Logging - * Extend Hertz logger based on logrus - * Implement tracing auto associated logs // 拓展 Hertz logger 接口,基于 logrus hook 机制,从 Context 里面提取相应的 trace context 放到日志里,通过这样的模式实现 trace context 和日志的串联 +- 默认提供开箱即用 OpenTelemetry Provider; +- 对 Hertz 做了一些 Instrumentation,主要有三点: + + - Tracing + - Support server and client Hertz http tracing + - Support automatic transparent transmission of peer service through http headers // 基于对端服务信息透传,实现服务拓扑能力 + - Metrics + - Support Hertz http metrics [R.E.D] // 做 http metrics 的埋点,实现一些服务的黄金指标 + - Support service topology map metrics [Service Topology Map] // 基于 http headers 透传对端服务信息,生成 Service Topology Map + - Support go runtime metrics + - Logging + - Extend Hertz logger based on logrus + - Implement tracing auto associated logs // 拓展 Hertz logger 接口,基于 logrus hook 机制,从 Context 里面提取相应的 trace context 放到日志里,通过这样的模式实现 trace context 和日志的串联 2. OpenTelemetry 目标是实现 Tracing/Metrics/Logging 三个数据的互联互通,但三者本身的成熟度上不同步,在社区状态中,Tracing 基本都是 Stable,Metrics 只有 API 和协议是 Stable 状态,Logging 是 Draft 状态。相关链接:https://opentelemetry.io/status/ 3. Hertz 并不是把 Logging 的 API 集成起来,而只是把协议里面提到的比如 Log Model、Trace ID 如何定义等规范集成,所以即使 Logging 没有达到一定成熟度,也可以使用。关于使用场景: -* 如果想要实现全链路观测,可以直接集成该。比如访问 Hertz Server 和 Kitex Server 会有一个简单的链路串联,可以输入一些自定义的属性,并且默认也会帮你输入根据 OpenTelemetry 语法规范做的、协议相关的属性; -* 如果想自动做请求维度的一些 RED 指标,比如计算 QPS,只要去把数据源导入就可以做相应的面板绘制; -* Runtime Metrics 也做了自动集成,可以在 Dashboard 里面绘制相应状态; -* 最新的 Jaeger 已经原生支持 OTLP Protocol 获取协议,相当于我们的库可以直接跟 Jaeger Collector 做集成,不需要用 OpenTelemetry Collector 做数据中转。 +- 如果想要实现全链路观测,可以直接集成该。比如访问 Hertz Server 和 Kitex Server 会有一个简单的链路串联,可以输入一些自定义的属性,并且默认也会帮你输入根据 OpenTelemetry 语法规范做的、协议相关的属性; +- 如果想自动做请求维度的一些 RED 指标,比如计算 QPS,只要去把数据源导入就可以做相应的面板绘制; +- Runtime Metrics 也做了自动集成,可以在 Dashboard 里面绘制相应状态; +- 最新的 Jaeger 已经原生支持 OTLP Protocol 获取协议,相当于我们的库可以直接跟 Jaeger Collector 做集成,不需要用 OpenTelemetry Collector 做数据中转。 使用场景:github.com/cloudwego/hertz-examples/tree/main/opentelemetry 4. 相关讨论: -* **Q:** 如果在 Hertz 使用 Obs 扩展,比如有一个 Trace ID,想快速找到有问题的请求,有没有可能就是把这个 Trace ID 或者是能够唯一标识这一次链路追踪的 ID 返回到 Response 里面去呢? -* **A:** 目前对于这种错误链路,可以在尾采样中做异常全采,不用借助 Response,可以直接在链路搜索里面找到相应的错误那条 Trace,然后看它上游或者下游哪些地方发生了异常。 +- **Q:** 如果在 Hertz 使用 Obs 扩展,比如有一个 Trace ID,想快速找到有问题的请求,有没有可能就是把这个 Trace ID 或者是能够唯一标识这一次链路追踪的 ID 返回到 Response 里面去呢? +- **A:** 目前对于这种错误链路,可以在尾采样中做异常全采,不用借助 Response,可以直接在链路搜索里面找到相应的错误那条 Trace,然后看它上游或者下游哪些地方发生了异常。 --- @@ -94,10 +94,10 @@ Fan Guangyu, Jacob953, Wang Yafeng, gova, Huang Xiaolong, Zhang Guiyuan, chenzBi 1. 源码解读活动一期结束,对于 RPC 相关基础知识整理了 1.6 万字,可以在 Community 仓库查看。 2. 源码解读活动二期已经开始,期间有四期直播分享: -* 了解 HTTP 框架的设计; -* 上手企业级 HTTP 框架 Hertz 的操作实践; -* CSG 一期源码解读优秀成员分享如何进行源码解读; -* 社区 Committer 和 Go 夜读作者分享,如何规划自己的代码学习和提升路径。 +- 了解 HTTP 框架的设计; +- 上手企业级 HTTP 框架 Hertz 的操作实践; +- CSG 一期源码解读优秀成员分享如何进行源码解读; +- 社区 Committer 和 Go 夜读作者分享,如何规划自己的代码学习和提升路径。 欢迎大家关注 CloudWeGo 公众号获取相关信息。 @@ -106,4 +106,3 @@ Fan Guangyu, Jacob953, Wang Yafeng, gova, Huang Xiaolong, Zhang Guiyuan, chenzBi 第一期直播回顾:https://meetings.feishu.cn/s/1i38ftnck0f18?src_type=3&disable_cross_redirect=true 第二期直播回顾:https://meetings.feishu.cn/s/1i3fsqit6jchu?src_type=3 - diff --git a/content/zh/community/meeting_notes/2022-07-28/_index.md b/content/zh/community/meeting_notes/2022-07-28/_index.md index 41b89c7627..9af0e14f50 100644 --- a/content/zh/community/meeting_notes/2022-07-28/_index.md +++ b/content/zh/community/meeting_notes/2022-07-28/_index.md @@ -25,10 +25,10 @@ description: > 1. Issue 地址:https://github.com/cloudwego/kitex/issues/511 2. 背景:对于用户而言,工程实践里面 RPC 异常分成两大类。 -* RPC 异常。即 RPC 请求失败,对应超时、协议错误、熔断或者限流等等情况; -* RPC 层面成功,用户层面异常。用户把请求发到下游,希望根据他的处理逻辑返回状态码给上游,上游可以通过这些状态码做一些额外处理。这种情况在 RPC 层面其实是请求成功,业务错误属于业务逻辑层面。因此服务监控建议对于 RPC 错误上报为请求失败,而业务层面错误,上报为请求成功,但上报 status_code 用于识别错误码。该能力对于工程实践具有一定的价值。 +- RPC 异常。即 RPC 请求失败,对应超时、协议错误、熔断或者限流等等情况; +- RPC 层面成功,用户层面异常。用户把请求发到下游,希望根据他的处理逻辑返回状态码给上游,上游可以通过这些状态码做一些额外处理。这种情况在 RPC 层面其实是请求成功,业务错误属于业务逻辑层面。因此服务监控建议对于 RPC 错误上报为请求失败,而业务层面错误,上报为请求成功,但上报 status_code 用于识别错误码。该能力对于工程实践具有一定的价值。 -起初,内部要求用户在 Thrift IDL 定义中定义全公司统一的 Base Response 字段,用户通过 Base Response 用户设置业务层面的状态码,我们把这个状态码上报,用户就可以通过监控看到业务层面出现的异常。但是考虑到开源后这套规范并不是很优雅,所以我们想定制一个通用的规范,让用户定义自己的异常。Kitex 本身支持多协议,这一套异常又不能和协议做耦合,因此我们要定义一套通用的接口。 +起初,内部要求用户在 Thrift IDL 定义中定义全公司统一的 Base Response 字段,用户通过 Base Response 用户设置业务层面的状态码,我们把这个状态码上报,用户就可以通过监控看到业务层面出现的异常。但是考虑到开源后这套规范并不是很优雅,所以我们想定制一个通用的规范,让用户定义自己的异常。Kitex 本身支持多协议,这一套异常又不能和协议做耦合,因此我们要定义一套通用的接口。 3. 接口定义:我们会定义一个 `bizStatusError` 接口。因为 gRPC 用户常用 Status 回传 Error,gRPC 无论是 RPC 真正的框架层面异常,还是用户自定义异常,都使用 Status,其实是没有办法区分的。我们给用户提供的是 gRPC 本身就提供给用户的,即通过 Status 构造 Error,因此我们也要对应地做支持。所以用户可以按照 gRPC 的 Status 实现接口,同时也可以实现 Kitex 定义的这套接口,Kitex 会根据接口判断是否有用户自定义异常,如果是 gRPC 的 Status,我们也会按照 gRPC 的规范通过 HTTPHeader 把错误写到 Header,通过 Header 回传。 4. 用户使用:服务端可以直接通过 `bizerror` 包构造 `bizStatusError`。调用端可以通过 `bizerror.FromError` 方法判断对端返回的是不是 `bizerror`。 @@ -42,10 +42,10 @@ description: > 1. Issue 地址:https://github.com/cloudwego/kitex/issues/531 2. 李纪昀提了关于 Kitex Tool 的改进建议。解答如下: -* 问题一:第一,Kitex 默认使用 go path 模式,如果没有指定 `-model` 参数,会认为当前项目是在 go path 下,之后尝试搜索 go path source 的相对路径,决定代码输出的前缀。现在 gomodule 已经使用比较广泛,我们是否可以默认在 gomodule 文件承载情况下,直接使用当前已知的 gomodule 不要求参数指定?这里的问题是我们内部还有很多项目不使用 gomodule,所以默认行为一旦改变,可能会产生很多 breaking change;第二,gomodule 不一定在当前目录,所以如果实现必须逐层向上搜索,但这可能会达不到预期的效果。 -* 问题二:我们内部可能会使用一些比较奇怪的 IDL 后缀。在它开发的早期,我们其实做了限制,入口的 IDL 必须是 `.thrift` 或者 `.proto` 。所以理论上这个是可以做支持的,根据 Thrift 还是 Proto 来确定当前的 Tag,只有在其他情况下才要求它必须指定一个 Tag,所以这是可以实现的。 -* 问题三:我们内部已经在考虑,即使不能合并,是否在两者的页面或者参数做一些统一的功能,此外生成代码的结构体将来是否能够复用也在研究中。 -* 问题四:起初设计 Kitex 也考虑过自定义模板,其实 Kitex 本身支持模版还是比较复杂的,因为 Kitex 并不主导生成代码的过程。它底层有 Protoc 和 Thriftgo 这样两个实际的编译器在做生成代码的工作。所以 Kitex 支持自定义模版还需要考虑两个底层的编译器是否能支持自定义模版的问题。而两个编译器都支持插件,所以自定义模版的功能完全可以用插件的功能实现。 +- 问题一:第一,Kitex 默认使用 go path 模式,如果没有指定 `-model` 参数,会认为当前项目是在 go path 下,之后尝试搜索 go path source 的相对路径,决定代码输出的前缀。现在 gomodule 已经使用比较广泛,我们是否可以默认在 gomodule 文件承载情况下,直接使用当前已知的 gomodule 不要求参数指定?这里的问题是我们内部还有很多项目不使用 gomodule,所以默认行为一旦改变,可能会产生很多 breaking change;第二,gomodule 不一定在当前目录,所以如果实现必须逐层向上搜索,但这可能会达不到预期的效果。 +- 问题二:我们内部可能会使用一些比较奇怪的 IDL 后缀。在它开发的早期,我们其实做了限制,入口的 IDL 必须是 `.thrift` 或者 `.proto` 。所以理论上这个是可以做支持的,根据 Thrift 还是 Proto 来确定当前的 Tag,只有在其他情况下才要求它必须指定一个 Tag,所以这是可以实现的。 +- 问题三:我们内部已经在考虑,即使不能合并,是否在两者的页面或者参数做一些统一的功能,此外生成代码的结构体将来是否能够复用也在研究中。 +- 问题四:起初设计 Kitex 也考虑过自定义模板,其实 Kitex 本身支持模版还是比较复杂的,因为 Kitex 并不主导生成代码的过程。它底层有 Protoc 和 Thriftgo 这样两个实际的编译器在做生成代码的工作。所以 Kitex 支持自定义模版还需要考虑两个底层的编译器是否能支持自定义模版的问题。而两个编译器都支持插件,所以自定义模版的功能完全可以用插件的功能实现。 --- @@ -80,4 +80,3 @@ description: > Hertz v0.2.0 发布! 相关链接:https://mp.weixin.qq.com/s/OOlO-ng4NVgnh32D2dj8Qw - diff --git a/content/zh/community/meeting_notes/2022-08-11/_index.md b/content/zh/community/meeting_notes/2022-08-11/_index.md index 7af7f3415e..6dfb29cc03 100644 --- a/content/zh/community/meeting_notes/2022-08-11/_index.md +++ b/content/zh/community/meeting_notes/2022-08-11/_index.md @@ -8,7 +8,7 @@ description: > **会议主题** :CloudWeGo 社区会议 8.11 -**参会人** :li-jin-gou, GuangmingLuo, pkumza, ag9920, lsjbd, sinnera, welkeyever, YangruiEmma, CoderPoet, joway, zstone12, Yin Xuran, bodhisatan, Fan Guangyu, Zhang Guiyuan, ppzqh, HeyJavaBean, simon0-o, baiyutang, rogerogers, skyenought, cloudwegoIce, cyyolo, baize, Hchenn, Ivnszn, LemonFish +**参会人** :li-jin-gou, GuangmingLuo, pkumza, ag9920, lsjbd, sinnera, welkeyever, YangruiEmma, CoderPoet, joway, zstone12, Yin Xuran, bodhisatan, Fan Guangyu, Zhang Guiyuan, ppzqh, HeyJavaBean, simon0-o, baiyutang, rogerogers, skyenought, cloudwegoIce, cyyolo, baize, Hchenn, Ivnszn, LemonFish **会前必读** :[官网](/);https://github.com/cloudwego @@ -60,13 +60,13 @@ description: > 1. 相关链接:https://mp.weixin.qq.com/s/x0Y7-gn9kwpoDQayS2bo3w 2. 背景:2021 年 9 月 CloudWeGo 正式开源,今年 9 月是正式开源一周年。一年内,CloudWeGo收获了 9000+ star,新增许多开源项目,还有即将新开源一个 Rust RPC 框架。我们会在开源一周年 Meetup 上介绍一年以来的开源历程。 3. 四个议题: - + - 高性能 RPC 框架 Kitex 内外统一的开源实践 - 大规模企业级 HTTP 框架设计和实践 - 新一代基于 Rust 语言的高性能 RPC 框架 - 开源社区的长期主义与新变化 - CloudWeGo 开源社区实践 + 4. 地点及参与方式: - + - 线上:直接报名参与,群里定时放出参与链接。 - 线下:北京字节跳动的工区,可以联系 cloudwegoIce 或刘佳同学注册报名。 - diff --git a/content/zh/community/meeting_notes/2022-09-08/_index.md b/content/zh/community/meeting_notes/2022-09-08/_index.md index 0d8b6cb566..01589e50b4 100644 --- a/content/zh/community/meeting_notes/2022-09-08/_index.md +++ b/content/zh/community/meeting_notes/2022-09-08/_index.md @@ -34,4 +34,3 @@ description: > 1. PR 地址:https://github.com/cloudwego/cloudwego.github.io/pull/337 2. Hertz 的反向代理分 Server 和 Client,原生 Go 的 SDK 里面拥有反向代理功能,社区也有反向代理的需求,目前在文档建设阶段,准备开源。具体内容可以点击 PR 地址查看。 - diff --git a/content/zh/community/meeting_notes/2022-09-22/_index.md b/content/zh/community/meeting_notes/2022-09-22/_index.md index eeb0d8fbcb..61e15dd6d7 100644 --- a/content/zh/community/meeting_notes/2022-09-22/_index.md +++ b/content/zh/community/meeting_notes/2022-09-22/_index.md @@ -23,11 +23,11 @@ description: > 1. 地址: -* bookinfo(附演示 demo) +- bookinfo(附演示 demo) https://github.com/cloudwego/biz-demo/pull/2 -* xDS +- xDS https://github.com/kitex-contrib/xds/pull/5/files -* 项目的工程架构 +- 项目的工程架构 github.com/CoderPoet/biz-demo/blob/feature%2Fbookinfo-proxyless-otel-demo/bookinfo/README_CN.md 2. 背景:在 biz-demo 中使用 kitex 和 hertz 重写 bookinfo 项目。实现的目的是为了以实战的方式演示如何使用 xDS 实现全链路的流量泳道。这个项目是复刻社区的 bookinfo 的部署模式,分为 Productpage、Reviews、Details 以及 Ratings,使用 kitex 和 hertz 完全重写。Productpage 是用 Hertz Server 写的,并且内嵌了 Kitex Client。 Kitex Client 集成了 xDS 的模块,主要负责与控制面的 Istiod 做交互,Istiod 可以动态地根据 xDS 下发路由规则。具体路由规则以及工程架构可点击上方链接查看。 @@ -50,6 +50,5 @@ description: > 1. 文档:[Hertz-pprof](https://r3478qhcm9.feishu.cn/docx/doxcnnD5J1EGhKfgp5QDNF0J34b?from=from_copylink) 2. 背景: -* pprof 是一个可以对 Go 程序的 CPU 内存以及 Goroutine 运行时进行动态信息采样的工具包,采样后以数据的方式展示,从而帮助开发人员进行快速地定位问题。常见的 HTTP 框架以及 gRPC 框架都会有相应的 pprof 扩展。这个扩展的底层实现依赖于 Go 语言内部 runtime/pprof 包,进一步的在 net/http/pprof 包里面对上述的 Go 语言包进行封装,对外提供 HTTP 的服务。 -* 在本项目中,为了在 Hertz 中引入 pprof 的能力,需要对 HTTP 包里面的 pprof 进一步封装。因为 HTTP 包里面 pprof 对外提供的是 http.Handler 以及 http.HandlerFunc,但是 Hertz 并不感知 HTTP 包里面的 http.Handler 以及 http.HandlerFunc,因此需要对其进行转换。具体实现过程请查看上方链接中的文档。 - +- pprof 是一个可以对 Go 程序的 CPU 内存以及 Goroutine 运行时进行动态信息采样的工具包,采样后以数据的方式展示,从而帮助开发人员进行快速地定位问题。常见的 HTTP 框架以及 gRPC 框架都会有相应的 pprof 扩展。这个扩展的底层实现依赖于 Go 语言内部 runtime/pprof 包,进一步的在 net/http/pprof 包里面对上述的 Go 语言包进行封装,对外提供 HTTP 的服务。 +- 在本项目中,为了在 Hertz 中引入 pprof 的能力,需要对 HTTP 包里面的 pprof 进一步封装。因为 HTTP 包里面 pprof 对外提供的是 http.Handler 以及 http.HandlerFunc,但是 Hertz 并不感知 HTTP 包里面的 http.Handler 以及 http.HandlerFunc,因此需要对其进行转换。具体实现过程请查看上方链接中的文档。 diff --git a/content/zh/community/meeting_notes/2022-10-20/_index.md b/content/zh/community/meeting_notes/2022-10-20/_index.md index 1707baff77..8368d5e95f 100644 --- a/content/zh/community/meeting_notes/2022-10-20/_index.md +++ b/content/zh/community/meeting_notes/2022-10-20/_index.md @@ -12,7 +12,7 @@ description: > **会前必读** :[官网](/) ; https://github.com/cloudwego -### 议程 1:CloudWeGo-Volo 0.2.0 新发版介绍 @Millione +### 议程 1:CloudWeGo-Volo 0.2.0 新发版介绍 @Millione 1. 相关链接:[Volo v0.2.0 正式发布:新增支持 Windows](https://mp.weixin.qq.com/s?__biz=Mzg2MTc0Mjg2Mw==&mid=2247490708&idx=3&sn=ae6d24cc1fa426b44c1ec774e8e0cc41&chksm=ce132ef4f964a7e2b469e34278e0dc7100e06e2e3df874e219b195896545778e6f11aa763602#rd) 2. **Volo 已经正式支持 Windows**。在 Volo 的共性方面,首先是关于错误处理,修复了对 Error 类型的约束,即在实现中间件时,对于 gRPC 以及 Thrift 返回的 Error 需要实现一个转换方法,就能转换到框架的 Error 类型中。这样有助于我们做整体的服务治理,还有一些错误判断之类的逻辑功能。 @@ -47,6 +47,4 @@ description: > 1. Issue: https://github.com/cloudwego/community/issues/45 2. CSG 三期是关于 8 月新开源的 Volo 框架以及 Volo 生态的一些项目,同时还有关注度非常高的 Monoio,都会在第三期里面进行相关的源码解读。第一期直播已经结束,可以关注 **CloudWeGo 公众号**回复 **“Volo"** 查看回放地址。 -3. 第三期的第二和第三场直播会和 Rustcc 社区合作,我们会也把自己的优质项目推到 Rust 基金会和 Rust 中文社区,和他们做比较深度的合作。后续也会有一些新的 Volo 生态和 Rust 生态的 Committer 和 Contributor 加入到我们的社区例会和社区组织中。欢迎大家持续关注。 - - +3. 第三期的第二和第三场直播会和 Rustcc 社区合作,我们会也把自己的优质项目推到 Rust 基金会和 Rust 中文社区,和他们做比较深度的合作。后续也会有一些新的 Volo 生态和 Rust 生态的 Committer 和 Contributor 加入到我们的社区例会和社区组织中。欢迎大家持续关注。 diff --git a/content/zh/community/meeting_notes/2022-11-03/_index.md b/content/zh/community/meeting_notes/2022-11-03/_index.md index 32ad7f9ee5..c23e64e1c5 100644 --- a/content/zh/community/meeting_notes/2022-11-03/_index.md +++ b/content/zh/community/meeting_notes/2022-11-03/_index.md @@ -27,14 +27,14 @@ description: > 官网:/zh/docs/kitex/tutorials/basic-feature/bizstatuserr/ 2. 背景:这是在 Kitex v0.4.3 提供的功能。我们内部对于用户自定义的异常和 RPC 异常做了区分,因此希望把这个功能提供给外部用户使用,能够将 RPC 错误和业务的错误区分开。在出现故障或排查问题的时候,可以方便找到是链路侧的故障还是业务侧的故障。因此我们对 Kitex 异常处理重新做了实现。 -3. 我们内置 `BizStatusErrorIface` 提供用户实现自定义异常接口,框架同时提供默认实现,用户只需要在 `ServiceHandler` 里返回 Error,就可以在 Kitex 处理的时候把它编码到 TTheader 或 grpc trailer 中。封装完成后通过 Server 传递到 Client 端,Kitex 在解码的时候会对 TTheader 或 trailer 里面字段做特殊处理,把它转成业务 Error,再返回给 Client。这种方式在中间件处理或治理采集时直接跳过了用户自定义异常的处理。因此我们通过在业务 handler 里面直接返回 `BizStatusErrorIface` 不会触发熔断和链路异常等情况,它仅用于用户之间业务 Error 的传递。 -4. TTheader 用法说明:https://github.com/cloudwego/kitex/pull/613/files 因为对外我们没有默认封装使用的 MetaHandler 和协议,自定义异常又借助于 TTheader 或 grpc Handler 的实现,所以 TTheader 协议的用户需要在 Server 里面初始化的时候,手动地初始化 TTheader 的 MetaHandler。在 Client 初始化的时候,同样指定 TTheader 协议,然后加载 TTheader 的 MetaHandler,这样才可以解析对应的字段。在 Server 使用的时候如果遇到业务异常,可以直接在 Handler 里面返回 Error。它主要包含的信息有:`StatusCode` 业务的状态码;`StatusMessage` 业务侧信息。Client 侧提供了对 Error 的识别,收到 Error 后,可以通过 `kerrors.FromBizStatusError` 把它转换成业务异常。收到业务异常后,我们就可以对不同的状态码做特殊的处理。 -5. grpc 的用法与之类似,grpc在 `StatusError` 里面提供了 Details 功能,所以我们在业务异常里面同样也提供了这个功能。用法可以参考代码示例:https://github.com/cloudwego/kitex/blob/develop/pkg/kerrors/bizerrors.go#L73。 +3. 我们内置 `BizStatusErrorIface` 提供用户实现自定义异常接口,框架同时提供默认实现,用户只需要在 `ServiceHandler` 里返回 Error,就可以在 Kitex 处理的时候把它编码到 TTheader 或 grpc trailer 中。封装完成后通过 Server 传递到 Client 端,Kitex 在解码的时候会对 TTheader 或 trailer 里面字段做特殊处理,把它转成业务 Error,再返回给 Client。这种方式在中间件处理或治理采集时直接跳过了用户自定义异常的处理。因此我们通过在业务 handler 里面直接返回 `BizStatusErrorIface` 不会触发熔断和链路异常等情况,它仅用于用户之间业务 Error 的传递。 +4. TTheader 用法说明:https://github.com/cloudwego/kitex/pull/613/files 因为对外我们没有默认封装使用的 MetaHandler 和协议,自定义异常又借助于 TTheader 或 grpc Handler 的实现,所以 TTheader 协议的用户需要在 Server 里面初始化的时候,手动地初始化 TTheader 的 MetaHandler。在 Client 初始化的时候,同样指定 TTheader 协议,然后加载 TTheader 的 MetaHandler,这样才可以解析对应的字段。在 Server 使用的时候如果遇到业务异常,可以直接在 Handler 里面返回 Error。它主要包含的信息有:`StatusCode` 业务的状态码;`StatusMessage` 业务侧信息。Client 侧提供了对 Error 的识别,收到 Error 后,可以通过 `kerrors.FromBizStatusError` 把它转换成业务异常。收到业务异常后,我们就可以对不同的状态码做特殊的处理。 +5. grpc 的用法与之类似,grpc在 `StatusError` 里面提供了 Details 功能,所以我们在业务异常里面同样也提供了这个功能。用法可以参考代码示例:https://github.com/cloudwego/kitex/blob/develop/pkg/kerrors/bizerrors.go#L73。 6. 补充:这个功能对于 Thrift 更建议的用法是 IDL 里面定义一个 Exception,这样用户可以很明确地构造它定义的 Exception。我们做这个支持不可能耦合于 Thrift 协议,PB 的 IDL 是没有这个能力的,因此提供了这样比较通用的方式。@YangruiEmma --- -### 议程三:Hertz Lark 扩展库介绍 @li-jin-gou +### 议程三:Hertz Lark 扩展库介绍 @li-jin-gou 1. 项目地址:https://github.com/hertz-contrib/lark-hertz @@ -44,4 +44,3 @@ Go SDK 说明文档:https://github.com/larksuite/oapi-sdk-go/blob/v3_main/READ 2. 背景:飞书开放平台有一个 Go SDK 说明文档,最初里面卡片和消息的回调配置介绍只有 Gin 框架的。有同学反馈找不到 Hertz 如何集成的说明,实际 Hertz 有这部分的能力,但是一直是内部的代码没有开源出来。之前用户通过这个平台点到 Go SDK 说明文档,并不能很方便地能找到对于 Hertz 的支持。所以和 Lark 负责 Go SDK 的同学说明情况后,和他们一起把 Lark 集成 Hertz 的能力开源出来。这个仓库目前放在了 Hertz 扩展库里面。如果大家感兴趣可以体验一下,在处理事件消息回调的情况下使用这个扩展会比较方便。 3. 使用场景:处理卡片和消息事件行为的回调。基于 oapi-sdk-go 做了一层封装,方便用户使用框架接入 SDK。关注 Hertz 的同学也更方便找到相关的内容。 - diff --git a/content/zh/community/past_activities/_index.md b/content/zh/community/past_activities/_index.md index 0390a48cc9..f62b2b0772 100644 --- a/content/zh/community/past_activities/_index.md +++ b/content/zh/community/past_activities/_index.md @@ -2,9 +2,9 @@ title: 往期活动 weight: 40 menu: - main: - weight: 40 - parent: "社区" + main: + weight: 40 + parent: "社区" --- - [CloudWeGo 开源一周年技术沙龙](https://juejin.cn/live/1040934) diff --git a/content/zh/community/weekly_report/10th/_index.md b/content/zh/community/weekly_report/10th/_index.md index 59285c201e..a2ac730512 100644 --- a/content/zh/community/weekly_report/10th/_index.md +++ b/content/zh/community/weekly_report/10th/_index.md @@ -4,6 +4,7 @@ linkTitle: CloudWeGo 第10期周报 weight: 1 description: > --- + **第10期周报** ![image](https://raw.githubusercontent.com/cloudwego/community/main/weekly_report/CloudWeGo_10th_weekly_report.png) diff --git a/content/zh/community/weekly_report/11th/_index.md b/content/zh/community/weekly_report/11th/_index.md index 2c7d940fab..608fd00e35 100644 --- a/content/zh/community/weekly_report/11th/_index.md +++ b/content/zh/community/weekly_report/11th/_index.md @@ -4,6 +4,7 @@ linkTitle: CloudWeGo 第11期周报 weight: 1 description: > --- + **第11期周报** ![image](https://raw.githubusercontent.com/cloudwego/community/main/weekly_report/CloudWeGo_11th_weekly_report.png) diff --git a/content/zh/community/weekly_report/12th/_index.md b/content/zh/community/weekly_report/12th/_index.md index a035e41fca..5659e8d9ef 100644 --- a/content/zh/community/weekly_report/12th/_index.md +++ b/content/zh/community/weekly_report/12th/_index.md @@ -8,5 +8,3 @@ description: > **第 12 期周报** ![image](https://raw.githubusercontent.com/cloudwego/community/main/weekly_report/CloudWeGo_12th_weekly_report.jpg) - - diff --git a/content/zh/community/weekly_report/13th/_index.md b/content/zh/community/weekly_report/13th/_index.md index ce7a0b12d8..cc3b5e1e57 100644 --- a/content/zh/community/weekly_report/13th/_index.md +++ b/content/zh/community/weekly_report/13th/_index.md @@ -8,5 +8,3 @@ description: > **第 13 期周报** ![image](https://raw.githubusercontent.com/cloudwego/community/main/weekly_report/CloudWeGo_13th_weekly_report.jpg) - - diff --git a/content/zh/community/weekly_report/14th/_index.md b/content/zh/community/weekly_report/14th/_index.md index 6a5894651c..7e31df3e13 100644 --- a/content/zh/community/weekly_report/14th/_index.md +++ b/content/zh/community/weekly_report/14th/_index.md @@ -8,6 +8,3 @@ description: > **第 14 期周报** ![image](https://raw.githubusercontent.com/cloudwego/community/main/weekly_report/CloudWeGo_14th_weekly_report.png) - - - diff --git a/content/zh/community/weekly_report/15th/_index.md b/content/zh/community/weekly_report/15th/_index.md index d55ef98c48..352fc98b0d 100644 --- a/content/zh/community/weekly_report/15th/_index.md +++ b/content/zh/community/weekly_report/15th/_index.md @@ -8,6 +8,3 @@ description: > **第 15 期周报** ![image](https://raw.githubusercontent.com/cloudwego/community/main/weekly_report/CloudWeGo_15th_weekly_report.png) - - - diff --git a/content/zh/community/weekly_report/16th/_index.md b/content/zh/community/weekly_report/16th/_index.md index 29d891de60..05fed2a10e 100644 --- a/content/zh/community/weekly_report/16th/_index.md +++ b/content/zh/community/weekly_report/16th/_index.md @@ -8,4 +8,3 @@ description: > **第 16 期周报** ![image](https://raw.githubusercontent.com/cloudwego/community/main/weekly_report/CloudWeGo_16th_weekly_report.png) - diff --git a/content/zh/community/weekly_report/17th/_index.md b/content/zh/community/weekly_report/17th/_index.md index ff09b137c0..2e6c09f609 100644 --- a/content/zh/community/weekly_report/17th/_index.md +++ b/content/zh/community/weekly_report/17th/_index.md @@ -8,4 +8,3 @@ description: > **第 17 期周报** ![image](https://raw.githubusercontent.com/cloudwego/community/main/weekly_report/CloudWeGo_17th_weekly_report.png) - diff --git a/content/zh/community/weekly_report/18th/_index.md b/content/zh/community/weekly_report/18th/_index.md index 262c5f7fe7..e04b967e2a 100644 --- a/content/zh/community/weekly_report/18th/_index.md +++ b/content/zh/community/weekly_report/18th/_index.md @@ -8,4 +8,3 @@ description: > **第 18 期周报** ![image](https://raw.githubusercontent.com/cloudwego/community/main/weekly_report/CloudWeGo_18th_weekly_report.png) - diff --git a/content/zh/community/weekly_report/19th/_index.md b/content/zh/community/weekly_report/19th/_index.md index e07a738bbd..8cd656b53d 100644 --- a/content/zh/community/weekly_report/19th/_index.md +++ b/content/zh/community/weekly_report/19th/_index.md @@ -8,4 +8,3 @@ description: > **第 19 期周报** ![image](https://raw.githubusercontent.com/cloudwego/community/main/weekly_report/CloudWeGo_19th_weekly_report.png) - diff --git a/content/zh/community/weekly_report/20th/_index.md b/content/zh/community/weekly_report/20th/_index.md index aa3d53aa52..a09db5f911 100644 --- a/content/zh/community/weekly_report/20th/_index.md +++ b/content/zh/community/weekly_report/20th/_index.md @@ -8,4 +8,3 @@ description: > **第 20 期周报** ![image](https://raw.githubusercontent.com/cloudwego/community/main/weekly_report/CloudWeGo_20th_weekly_report.png) - diff --git a/content/zh/community/weekly_report/21th/_index.md b/content/zh/community/weekly_report/21th/_index.md index f27e0d3ba4..c8d7f4b615 100644 --- a/content/zh/community/weekly_report/21th/_index.md +++ b/content/zh/community/weekly_report/21th/_index.md @@ -8,4 +8,3 @@ description: > **第 21 期周报** ![image](https://raw.githubusercontent.com/cloudwego/community/main/weekly_report/CloudWeGo_21th_weekly_report.png) - diff --git a/content/zh/community/weekly_report/5th/_index.md b/content/zh/community/weekly_report/5th/_index.md index 870e3a083e..d1a78bef23 100644 --- a/content/zh/community/weekly_report/5th/_index.md +++ b/content/zh/community/weekly_report/5th/_index.md @@ -4,6 +4,7 @@ linkTitle: CloudWeGo 第05期周报 weight: 1 description: > --- + **第5期周报** ![image](https://raw.githubusercontent.com/cloudwego/community/main/weekly_report/CloudWeGo_5th_weekly_report.png) diff --git a/content/zh/community/weekly_report/6th/_index.md b/content/zh/community/weekly_report/6th/_index.md index 9848ca64d5..cbbde41e6c 100644 --- a/content/zh/community/weekly_report/6th/_index.md +++ b/content/zh/community/weekly_report/6th/_index.md @@ -4,6 +4,7 @@ linkTitle: CloudWeGo 第06期周报 weight: 1 description: > --- + **第6期周报** ![image](https://raw.githubusercontent.com/cloudwego/community/main/weekly_report/CloudWeGo_6th_weekly_report.png) diff --git a/content/zh/community/weekly_report/7th/_index.md b/content/zh/community/weekly_report/7th/_index.md index 2965266b29..970b608ee4 100644 --- a/content/zh/community/weekly_report/7th/_index.md +++ b/content/zh/community/weekly_report/7th/_index.md @@ -4,6 +4,7 @@ linkTitle: CloudWeGo 第07期周报 weight: 1 description: > --- + **第7期周报** ![image](https://raw.githubusercontent.com/cloudwego/community/main/weekly_report/CloudWeGo_7th_weekly_report.png) diff --git a/content/zh/community/weekly_report/8th/_index.md b/content/zh/community/weekly_report/8th/_index.md index 40b2f6fce1..227992d7c2 100644 --- a/content/zh/community/weekly_report/8th/_index.md +++ b/content/zh/community/weekly_report/8th/_index.md @@ -4,6 +4,7 @@ linkTitle: CloudWeGo 第08期周报 weight: 1 description: > --- + **第8期周报** ![image](https://raw.githubusercontent.com/cloudwego/community/main/weekly_report/CloudWeGo_8th_weekly_report.png) diff --git a/content/zh/community/weekly_report/9th/_index.md b/content/zh/community/weekly_report/9th/_index.md index a3cb76f421..ab737fef81 100644 --- a/content/zh/community/weekly_report/9th/_index.md +++ b/content/zh/community/weekly_report/9th/_index.md @@ -4,6 +4,7 @@ linkTitle: CloudWeGo 第09期周报 weight: 1 description: > --- + **第9期周报** ![image](https://raw.githubusercontent.com/cloudwego/community/main/weekly_report/CloudWeGo_9th_weekly_report.png) diff --git a/content/zh/community/weekly_report/_index.md b/content/zh/community/weekly_report/_index.md index cad17a3149..fabcd3d1a3 100644 --- a/content/zh/community/weekly_report/_index.md +++ b/content/zh/community/weekly_report/_index.md @@ -6,4 +6,3 @@ menu: weight: 30 parent: "社区" --- - diff --git a/content/zh/cooperation/_index.md b/content/zh/cooperation/_index.md index 7acdfad6c3..9c29898418 100644 --- a/content/zh/cooperation/_index.md +++ b/content/zh/cooperation/_index.md @@ -1,6 +1,6 @@ --- -title: '案例' -linkTitle: '用户案例' +title: "案例" +linkTitle: "用户案例" menu: main: weight: 40 diff --git a/content/zh/cooperation/feishu.md b/content/zh/cooperation/feishu.md index a822e6be06..f424739aad 100644 --- a/content/zh/cooperation/feishu.md +++ b/content/zh/cooperation/feishu.md @@ -18,6 +18,7 @@ weight: 3 它通过引入 Kitex 泛化调用对飞书管理后台进行平台化改造,使之变为业务网关,提供一套统一的标准和通用服务,让有管控诉求的套件业务方能快速实现能力集成,并且提供一致的体验。最终实现了飞书管理后台作为企业统一数字化管理平台的愿景。 本文将从三个方面为大家讲解 Kitex 泛化调用在飞书管理后台平台化改造过程中的落地实践: + 1. 架构和挑战,即飞书管理后台单体架构面临的各种挑战; 2. 平台化构想,即飞书管理后台平台化构想和架构升级; 3. 平台化实现,包括微前端技术架构、泛化调用实践和功能扩展。 @@ -85,6 +86,7 @@ Service Mesh 可以看成是 API Gateway 的去中心化实现方式,用来解 ### 新的框架 下面介绍一下我们的新架构,它主要包括: + 1. **Gaia 控制面**。我们增加了 Gaia 平台(基于 Hertz 框架的 Web 服务)来作为我们整个 Admin 的控制系统,负责整体的发布和管控需求,包括接口的生命周期管理、微应用生命周期管理、监控告警、业务线接入、多环境发布等。 2. **前端架构**。前端采用微前端架构,各个业务方通过构建微应用接入 Admin 基座,使用统一封装好的组件库实现前端页面。 3. **后端架构**。后端使用字节通用 BAM 规范,通过泛化调用的方式打通 Admin 和各接入业务方服务,并抽象公共组件以插件的方式进行功能扩展。 @@ -100,6 +102,7 @@ Service Mesh 可以看成是 API Gateway 的去中心化实现方式,用来解 ### Gaia 平台功能 Gaia 平台主要包括以下功能: + 1. **业务线管理**。业务线是实现以业务为维度进行接入 Admin 而提出的概念。通过业务线来聚合业务为维度的所有资源,相关资源包括微应用、菜单、接口、监控等。图中就是业务线管理的菜单页面。 ![feishu6](/img/users/feishu/feishu6.png) @@ -178,6 +181,7 @@ Kitex 和 Hertz 还不能支持接口编排的功能,所以我们通过自定 ## 成果 最后给大家介绍一下我们的演进成果,主要有以下三点: + 1. **业务迭代加速**。Admin 不再关注其他业务线的需求,更加专注于自身的迭代需求。各个业务方发布完全隔离,使得他们不再依赖 Admin,加快了 Admin 整体的业务功能迭代速度。 2. **研发效率提升**。丰富的前后端组件和简单的接入方式,业务方不需要再花费时间熟悉我们的代码仓库,使得业务方接入更加便捷,研发效率大大提升。 3. **工程质量提高**。 @@ -188,6 +192,7 @@ Kitex 和 Hertz 还不能支持接口编排的功能,所以我们通过自定 ## 未来规划 我们目前制定了一些未来的发展规划,主要有以下四点: + 1. 开放更多的组件,让接入的业务方聚焦在业务逻辑本身,例如组织管理里面的选人组件,之前需要各个业务方自己内部实现,之后我们会提供一套公共组件,业务方可以直接使用,包括消息中心、任务管理、安全风控、短信邮件等; 2. 完善服务治理和运维能力,包括灰度、降级、限流、精细化大盘等; 3. 建设通用的静态页面托管解决方案,为开发者提供便捷、稳定、高扩展性的静态页面托管服务; diff --git a/content/zh/cooperation/foundersc.md b/content/zh/cooperation/foundersc.md index 19424cfce2..5413c9e646 100644 --- a/content/zh/cooperation/foundersc.md +++ b/content/zh/cooperation/foundersc.md @@ -8,12 +8,14 @@ weight: 7 > 本文根据2024年3月30日在北京举办的“云原生✖️AI时代的微服务架构与技术实践”CloudWeGo 技术沙龙北京站活动方正证券 金融科技工程院高级研发工程师刘义的演讲《金融科技 Go 微服务建设实践》整理而来。 概述:本文将详细介绍方正证券金融科技工程院在云原生微服务建设实践经验,分享包含 3 个方面: + 1. 微服务治理工作 2. 微服务可观测性工作 3. 微服务接口管理 -上述能力统一集成到了方正公司的夸克开发平台上。 + 上述能力统一集成到了方正公司的夸克开发平台上。 ## 方正证券微服务建设实践介绍 + 2023 年年初我们启动了微服务体系建设,其中注册中心采用的 [ZooKeeper][ZooKeeper],Web 和 RPC 应用框架分别采用的 CloudWeGo 的 [Hertz][Hertz] 和 [Kitex][Kitex]。 目前我们进入到了微服务建设的深水区,主要涉及到**微服务治理**,**可观测性能力**,**接口管理**等相关工作内容,下面将分别从概念、实现原理等方面来详细介绍。 @@ -21,30 +23,34 @@ weight: 7 ## 微服务治理能力建设 ### 概念 + 微服务架构下,随着业务量的逐步增加,服务的数量也会逐步增加。基于此背景,随着业务的发展,对服务的管控难度会越来越大,服务治理的作用就是为了解决服务拆分所引发的一系列问题,以让服务更稳定地运行,涉及的主题包含了服务注册与发现、负载均衡、服务熔断、服务降级、服务限流等。 夸克平台提供的超时、重试以及服务端限流的功能,均基于 [Kitex][Kitex] 的相关能力而来,目前所使用的注册中心为 ZooKeeper(缩写 zk),因此相关的动态配置也是借助 zk 来实现,通过将配置写入到 zk,来通知 server 端、client 端完成相关功能的开启。 ### 介绍 + 1. 流量控制 - + 流量控制的粒度为服务级别,下图所示中,该服务每秒最多处理1000个请求,超额的请求将被直接关闭掉: ![huaxing_ratelimit](/img/users/foundersc/foundersc1.png) 2. 重试配置 - + 重试配置的粒度为方法级别,用来配置当前服务对指定服务的某个方法发出的请求失败的情况下,如何进行重试: ![huaxing_retry](/img/users/foundersc/foundersc2.png) 3. 超时配置 - + 超时配置的粒度为方法级别,用来配置当前服务对指定服务的某个方法请求的最大耗时,超过该值时,当前服务会断开连接: ![huaxing_timeout](/img/users/foundersc/foundersc3.png) 各个配置的具体作用详见配置说明 ### 实现原理与细节 + server 端、client 端均通过扩展 [Kitex][Kitex] 的 suite 来完成相关配置的动态注入。 #### server端 + 通过如下代码对 Kitex server 进行配置: ```go @@ -63,6 +69,7 @@ func (s *zooKeeperServerSuite) Options() []server.Option { ``` 基于以上内容,可以发现,server 端的 suite 中默认只配置了 limiter,[Kitex][Kitex] 框架目前只支持两类 limiter: + 1. Connections limiter(限制最大连接数量) 2. Qps limiter(限制最大qps) @@ -96,6 +103,7 @@ zooKeeperClient.RegisterConfigCallback(context.Background(), path, uniqueID, onC ``` #### client端 + 类似 server 端,client 端也有同样的配置: ```go @@ -114,6 +122,7 @@ func (s *zooKeeperClientSuite) Options() []client.Option { return opts } ``` + 即,客户端支持重试、超时、熔断三种动态配置。相关的处理均是通过zk客户端的回调方法来达到动态更新的效果。 **超时配置的额外说明** @@ -133,6 +142,7 @@ func WithRPCTimeout(dest, src string, zooKeeperClient zooKeeper.Client, opts uti } } ``` + 最终通过调用 Kitex 提供的`client.WithTimeoutProvider`方法来完成超时相关的具体配置。对于超时,存在以下不同的配置方法: ```go @@ -152,23 +162,25 @@ func WithTimeoutProvider(p rpcinfo.TimeoutProvider) Option { 其中,`WithTimeoutProvider`设置的超时时间会被`WithRPCTimeout`、`WithConnectTimeout`设置的值所覆盖,因此如果在创建 Kitex client 时,调用过`WithRPCTimeout`或者`WithConnectTimeout`,会导致动态配置无法生效。 ### 配置说明 + #### 超时 + 对应的zk节点:`/kitexConfig/{ClientName}/{ServiceName}/rpc_timeout` 写入的配置格式如下: ```json { - "*": { - "conn_timeout_ms": 100, - "rpc_timeout_ms": 800 - }, - "GetDemoInfo": { - "rpc_timeout_ms": 300 - }, - "GetDemoInfo3": { - "rpc_timeout_ms": 300 - } + "*": { + "conn_timeout_ms": 100, + "rpc_timeout_ms": 800 + }, + "GetDemoInfo": { + "rpc_timeout_ms": 300 + }, + "GetDemoInfo3": { + "rpc_timeout_ms": 300 + } } ``` @@ -177,71 +189,77 @@ func WithTimeoutProvider(p rpcinfo.TimeoutProvider) Option { `rpc_timeout_ms`:一次 rpc 调用的最大用时; #### 重试 + 对应的zk节点:`/kitexConfig/{ClientName}/{ServiceName}/retry` 写入的配置格式如下: ```json { - "GetDemoInfo": { - "enable": true, - "type": 0, - "failure_policy": { - "stop_policy": { - "max_retry_times": 2, - "max_duration_ms": 9000, - "cb_policy": { - "error_rate": 0.1 - } - } + "GetDemoInfo": { + "enable": true, + "type": 0, + "failure_policy": { + "stop_policy": { + "max_retry_times": 2, + "max_duration_ms": 9000, + "cb_policy": { + "error_rate": 0.1 } - }, - "GetDemoInfo5": { - "enable": true, - "type": 0, - "failure_policy": { - "stop_policy": { - "max_retry_times": 2, - "max_duration_ms": 9000, - "cb_policy": { - "error_rate": 0.1 - } - } + } + } + }, + "GetDemoInfo5": { + "enable": true, + "type": 0, + "failure_policy": { + "stop_policy": { + "max_retry_times": 2, + "max_duration_ms": 9000, + "cb_policy": { + "error_rate": 0.1 } + } } + } } ``` **字段含义** -| 配置项 | 默认值 | 说明 | 限制 | -|-----------------|-----|-----------------------------------------------------------------------------|-------------| -| max_retry_times | 2 | 最大重试次数,不包含首次请求。如果配置为 0 表示停止重试。 | 合法值:[0-5] | -| max_duration_ms | 0 | 累计最大耗时,包括首次失败请求和重试请求耗时,如果耗时达到了限制的时间则停止后续的重试。0 表示无限制。注意:如果配置,该配置项必须大于请求超时时间。 | | -| error_rate | 10% | 重试熔断错误率阈值, 方法级别请求错误率超过阈值则停止重试。 | 合法值:(0-30%] | +| 配置项 | 默认值 | 说明 | 限制 | +| --------------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------- | --------------- | +| max_retry_times | 2 | 最大重试次数,不包含首次请求。如果配置为 0 表示停止重试。 | 合法值:[0-5] | +| max_duration_ms | 0 | 累计最大耗时,包括首次失败请求和重试请求耗时,如果耗时达到了限制的时间则停止后续的重试。0 表示无限制。注意:如果配置,该配置项必须大于请求超时时间。 | | +| error_rate | 10% | 重试熔断错误率阈值, 方法级别请求错误率超过阈值则停止重试。 | 合法值:(0-30%] | #### 限流 + 此配置为服务全局配置,因此 zk 节点路径只包含 serviceName:`/kitexConfig/{ServiceName}/limit` 写入的配置格式如下: ```json { - "qps_limit": 100 + "qps_limit": 100 } ``` ## 微服务可观测性能力建设 + ### 概念 + 服务观测性建设指的是在分布式系统中建立和完善监控、日志、追踪等工具和技术,以便全面、及时地了解系统的运行状态和性能指标。 一个完善的观测性工具,可以为业务系统带来诸多好处: + 1. 能及时发现和解决问题; 2. 使团队能够更清晰地了解系统的整体运行情况和内部交互关系; 3. 可以了解系统的负载情况、资源利用率和趋势变化,以支持容量规划和资源优化; 4. 通过日志和追踪系统记录系统的操作日志和请求轨迹,可以跟踪和分析用户操作行为、异常请求和安全事件,提高系统的安全性和可靠性。 ### 介绍 + 服务详细信息,用来展示服务本身的整体运行情况,包含了黄金监控指标(QPS、Latency和 Error Ratio)、SLO 和 runtime相关信息等: ![huaxing_grafana](/img/users/foundersc/foundersc4.png) @@ -252,6 +270,7 @@ func WithTimeoutProvider(p rpcinfo.TimeoutProvider) Option { ![huaxing_trace](/img/users/foundersc/foundersc6.png) ### 实现原理与细节 + ![huaxing_otel](/img/users/foundersc/foundersc7.jpg) 目前模板代码中已经集成了 [OpenTelemetry][OpenTelemetry] 客户端,生成的 [Hertz][Hertz]、[Kitex][Kitex] 服务默认拥有可观测数据(Metrics + Tracing)上报能力。 @@ -262,11 +281,13 @@ func WithTimeoutProvider(p rpcinfo.TimeoutProvider) Option { > OpenTelemetry 提供独立于供应商的 SDK、API 和工具。OpenTelemetry 正在快速成为云原生应用程序领域内主导的可观测性遥测数据标准。如果组织想要做好准备以满足未来的数据需求,而且不想被锁定到某一特定供应商,也不想受限于其既有技术,那么采用 OpenTelemetry 对其至为关键。 #### Trace( 跟踪) + Tracing 提供了从请求开始接收到处理完毕的整个生命周期的全貌。 服务在接收到请求后,从元信息(Kitex)或 http header(Hertz)中启用链路追踪。如果元信息或 HTTP header 中没有 Tracing 信息,将自动启用新的链路追踪。服务进程内通过 context 来传递链路信息。 接入方式: + ```go // for Hertz tracer, cfg := hertztracing.NewServerTracer() @@ -287,26 +308,29 @@ Tracing 信息上报到 OpenTelemetry Collector 中,然后透传给 Jaeger。 ```json { - "file": "get_repositories.go:33", - "func": "gitlab.fzzqft.com/ifte-quark/quark-api/biz/service.(*GetRepositoriesService).Run", - "level": "info", - "msg": "GetRepositoriesService Run req: page:1 limit:10 service_name:\"kitex\"", - "span_id": "aa26bab58cdf6806", - "time": "2024-04-23 15:59:40.609", - "trace_flags": "01", - "trace_id": "f714dbe2a96b1882dfc4b81909e55643" + "file": "get_repositories.go:33", + "func": "gitlab.fzzqft.com/ifte-quark/quark-api/biz/service.(*GetRepositoriesService).Run", + "level": "info", + "msg": "GetRepositoriesService Run req: page:1 limit:10 service_name:\"kitex\"", + "span_id": "aa26bab58cdf6806", + "time": "2024-04-23 15:59:40.609", + "trace_flags": "01", + "trace_id": "f714dbe2a96b1882dfc4b81909e55643" } ``` 日志被采集处理后,可以在日志平台上通过 `trace_id` 来查询整个链路的相关日志信息。 #### Metrics(指标) + Metrics 是衡量系统性能和行为的关键数据,如请求速率、响应时间、错误率等。指标通常被收集、聚合和可视化,以便监视系统的健康状况并进行趋势分析。 目前,每个服务各自上报自身的 Metrics 数据,统一存储在 Prometheus/VictoriaMetrics 中,最终使用 grafana 形成监控面板。 下面通过QPS、请求耗时、错误率这三个常见的服务描述指标来展示如何使用服务上报的 Metrics 数据。 + - QPS:基于QPS的定义,我们只需要获取到实时请求数量,即可计算出 QPS,上报的数据中,`http_server_duration_count` 的值与请求数量一致,因此可以使用此 Metric 来完成 QPS 的计算。 + ```bash sum(rate(http_server_duration_count{service_name="$service_name"}[$__rate_interval])) ``` @@ -314,8 +338,9 @@ Metrics 是衡量系统性能和行为的关键数据,如请求速率、响应 上述 promQL 中,rate 函数的作用是计算某个 Metric 在指定时间段内的增长率,最终得到的结果为指定时间段内的平均请求数量。 - 请求耗时:由于是一个统计数据,这里选择使用平均值来表示服务请求的耗时情况,通过指定时间段内的所有请求总耗时➗指定时间段内的请求数量得到平均耗时: + ```bash - sum(rate(http_server_duration_sum{service_name="$service_name"}[$__rate_interval])) by (application) / + sum(rate(http_server_duration_sum{service_name="$service_name"}[$__rate_interval])) by (application) / sum(rate(http_server_duration_count{service_name="$service_name"}[$__rate_interval])) by (application) ``` @@ -326,21 +351,27 @@ Metrics 是衡量系统性能和行为的关键数据,如请求速率、响应 ``` #### 拓扑图 + 通过聚合中提到的 Metric 数据来展示整体的服务间依赖关系,上报数据中有`service_name`以及`source`和`target`信息,通过 PromSQL 的`sum`操作符即可获取到服务上下游信息。 ## 微服务接口管理能力建设 + ### 概念 + - IDL - + 接口描述语言(Interface Description Language,缩写IDL),是用来描述软件组件接口的一种计算机语言。 IDL通过一种独立于编程语言的方式来描述接口,使得在不同平台上运行的对象和用不同语言编写的程序可以相互通信交流。 + - 接口管理 - + Kitex(RPC)服务均基于IDL来实现,接口管理平台主要提供接口平台化的方式来管理RPC服务的IDL产物,便于开发者管理和调用RPC接口。 + - 接口测试 - + Kitex(RPC)服务存在测试不可达的情况,接口测试平台用户解决该问题,便于测试、开发通过平台发起RPC请求完成调试。 ### 介绍 + - 接口管理平台(操作方法见图示) ![huaxing_interface_1](/img/users/foundersc/foundersc8.png) ![huaxing_interface_2](/img/users/foundersc/foundersc9.png) @@ -349,11 +380,13 @@ Metrics 是衡量系统性能和行为的关键数据,如请求速率、响应 ![huaxing_interface_test](/img/users/foundersc/foundersc11.png) ### 实现原理与细节 + - 接口管理 - + 此前我们使用的是独立仓库配合 gitlabci 的方式来管理 [Kitex][Kitex] 服务的 IDL 产物: ![huaxing_interface_impl](/img/users/foundersc/foundersc12.jpg) 在实际使用过程中,存在以下痛点: + 1. 调用方需要通过小窗方式(私聊)获取IDL产物仓库的地址、分支或版本号 2. 服务提供方式需要同时关注服务项目仓库和对应的产物仓库 3. Gitlabci 强依赖 runner,新的 group 需要找管理员配置才可用 @@ -363,17 +396,19 @@ Metrics 是衡量系统性能和行为的关键数据,如请求速率、响应 ![huaxing_interface_platform](/img/users/foundersc/foundersc13.jpg) 服务在构建打包时,触发 IDL 产物更新流程,平台将自动检测服务类型,并生成对应的 IDL 产物提交到 gitlab 独立仓库中。用户也可以在平台中手动创建或更新 IDL 产物。调用方只需复制执行 import 路径命令,就能获取对应版本的服务依赖。 + - 接口测试 ![huaxing_interface_test_logic](/img/users/foundersc/foundersc14.jpg) 基于 Kitex PB 的 JSON 映射泛化调用实现。用户在平台上选择对应服务和接口,平台自动解析对应的 IDL 文件,给出默认的请求参数(json 格式)。发送请求后,平台通过泛化调用的方式向目标服务发起一次 RPC 请求,并将结果返回。 ## 小结 + 目前的微服务体系已经能满足大部分的技术类需求,但是在云原生的体系之下计划走得更远一些: + 1. 服务治理,依赖云原生服务网格(ServiceMesh)能力来治理流量,同时把其他应用框架的东西向的流量一起纳入进来。 2. 可观测性,OpenTelemetry 是一套与语言无关、与应用框架无关的解决方案,通过统一语义,计划将 Java 的 Web(Springboot)和 RPC(Dubbo)体系一起纳管进来。 3. 接口管理,未来计划将 RPC 和 HTTP 接口统一管理,自动生成接口用例。 - [Kitex]: http://github.com/cloudwego/kitex [Hertz]: http://github.com/cloudwego/hertz [OpenTelemetry]: https://opentelemetry.io/ diff --git a/content/zh/cooperation/huaxingsec.md b/content/zh/cooperation/huaxingsec.md index 73d35f66b6..83765db2c1 100644 --- a/content/zh/cooperation/huaxingsec.md +++ b/content/zh/cooperation/huaxingsec.md @@ -15,12 +15,12 @@ weight: 1

本文将从以下 4 个方面介绍华兴证券基于 Kitex 在多机房 K8s 集群下的实践经验,包括: + 1. 针对 Kitex 的可观测性系统搭建经验; 2. 服务压力测试中遇到的问题以及解决方案; 3. Kitex 的不同连接类型在 K8s 同集群/跨集群调用下的一些问题和解决方案; 4. 实践中遇到的其他问题以及解决方案; - ## Kitex 的可观性系统搭建 ### 华兴证券 CloudWeGo-Kitex 使用情况 @@ -92,7 +92,7 @@ Tracing 一般只关注调用耗时,然而一条链路中可能出现各种错 - Kitex RPC 返回的 err(Conn Timeout、Read Timeout 等); - IDL 里自定义的业务 Code(111: 用户不存在)。 -2.HTTP + 2.HTTP - 返回的 HTTP 状态码(404、503); - JSON 里的业务 Code(-1: 内部错误)。 @@ -187,6 +187,7 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 ![huaxing18](/img/users/huaxingsec/huaxing18.png) 我们讨论了几种解决方案: + 1. 修改超时配置。然而,交易日的 9:30-9:35 有⼀堆集中交易请求,突发的流量,耗时长了体验不好,可能会影响 APP 收入,我们希望系统性能保持稳定。 2. 进行连接耗时的优化。然而 Kitex 已经使用了 Epoll 来处理创建连接的事件,作为使用方,进一步优化的难度和成本都太大。 3. MaxidleTimeout 参数改成无限大?比如先创建一个足够大的池,然后随着用户请求,池变得越来越大,最终稳定下来。但是每次服务升级之后,这个池就空了,需要慢慢恢复。 @@ -199,6 +200,7 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 ![huaxing20](/img/users/huaxingsec/huaxing20.png) 当时 CloudWeGo 团队针对我们公司建了企业用户交流群,于是我们就向群里的 Kitex 研发提了连接预热的需求。其开发之后提供了连接预热个数的选项。我们也进行了测试。按照 QPS=2000 进行测试, + - WARM_UP_CONN_NUM=0:大约 1s 报错; - WARM_UP_CONN_NUM=100:大约 4s 报错; @@ -210,6 +212,7 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 ![huaxing22](/img/users/huaxingsec/huaxing22.png) 本章小结如下: + - Kitex v0.0.8:域名模式下存在连接池失效问题,v0.1.3 中修复; - Kitex v0.1.3:可进一步通过连接预热功能提高系统性能。 @@ -224,6 +227,7 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 那么,当长连接池数目比较大(比如数千),且上游较多(各种服务、每个都多副本,加起来可能数十个)的情况下,请求高峰时段可能导致上游宿主机的源端口不够用。同集群内跨机器调用走了 vxlan,因此没有这个问题。 解决方案有两类: + - 硬件方案:机器; - 软件方案:对于下游为 Kitex 服务,改用 Mux 模式(这样少量连接就可以处理大量并发的请求)。下游不是 Kitex 框架,因为 Mux 是私有协议,不支持非 Kitex。此时可考虑增加下游服务的 LB 数量,比如每个 LB 上分配多个端口。 @@ -236,6 +240,7 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 上游容器←→ClusterIP(服务的虚拟 IP)←→下游容器 然后我们看看滚动升级流程: + 1. 新容器启动。 2. 新容器 Readiness Check 通过,之后做两件事情: - 更新 Endpoints 列表:新增新容器,删除旧容器; @@ -247,16 +252,19 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 经过步骤 3 之后,已有的连接仍然能够正常工作(因为旧容器 rs 未删),但新建的连接会走到新的容器上(因为旧容器权重 =0)。 在 Service 模式下,上游通过一个固定的 IP: 端口来访问下游,当下游滚动升级的时候,上游看到的地址并未变化,即无法感知到滚动升级。于是,下游即使有优雅退出,但上游并不知道下游开始优雅退出了。之后可能的情况是: + 1. 下游发现连接繁忙,一直没有主动关闭,导致 K8s 配置的优雅升级时间超时,强制 Kill 进程,连接关闭,上游报错。 2. 下游发现连接空闲,主动关闭,然而客户端在关闭之前恰好拿到了连接(且认为可用),然后发起请求,实际上由于连接关闭,发起请求失败报错。 针对此问题,解决方案如下: + 1. 同集群调用:改用 Headless Service 模式(结合 DNSResolver):通过 DNS 列表的增删来感知下游变动; 2. 跨集群调用:借鉴 HTTP2 的 GOAWAY 机制。 ![huaxing23](/img/users/huaxingsec/huaxing23.png) 具体,可采用如下方式: + 1. 收到 sigTerm 的下游直接告诉上游(通过之前建立的 Conn1),同时下游继续处理发来的请求。 2. 上游收到关闭信息之后: - 新请求通过新建 Conn2 来发; @@ -269,6 +277,7 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 在 Kitex 团队开发期间,我们测下 Kitex 已有版本对 Headless Service 模式下的滚动升级功能。 测试方案如下: + - Kitex 版本 v0.1.3; - 上下游均为 Mux 模式; - 上游的加了个自定义 DNSResolver,刷新时间为 1s,加日志打印解析结果; @@ -280,6 +289,7 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 ![huaxing24](/img/users/huaxingsec/huaxing24.png) 时序分析如下: + - 旧下游收到 sigTerm,开始 Sleep 10s; - 上游解析到旧下游的 IP,向旧下游发起请求; - DNS 规则更新:旧上游 IP 解析项消失,新下游解析项出现; @@ -289,6 +299,7 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 可见报错时旧下游还未执行退出逻辑,排除旧下游主动关闭连接。请求旧下游期间,且此时解析到新容器 IP(移除了旧容器 IP),报错是因为还没到退出逻辑的时候。因此推测,解析条目变化导致了报错。 根据推测,结合代码(Kitex 客户端部分)分析,可能出现以下并发问题: + - 【协程1】客户端从 Mux池里取出 conn1,即将发起请求(所以没有机会再检查 conn1 状态了); - 【协程2】DNS 更新,移除了 IP,于是 Clean 方法中关闭了 conn1; - 【协程1】客户端用 conn1 发起请求,导致报错 conn closed。 @@ -313,6 +324,7 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 报错:INFO[0050] "{\"code\":-1,\"message\":\"remote or network error: conn closed\"}"。 时序分析为: + 1. 旧下游收到 sigTerm,开始 sleep 10s。 2. IPVS规则变化: - 新下游 weight=1,ac=0,inac=0; @@ -340,6 +352,7 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 1. 同集群调用:可用 Headless Service 模式,由于 DNS 解析能够得到所有 POD,路由没问题。 2. 跨集群调用:不在同集群内, Headless Service 模式无效,考虑如下方案: + - 方案1:修改服务发现机制。 优点:Kitex 无需改动。 缺点:增加依赖项(服务发现组件)。 @@ -351,6 +364,7 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 缺点:需要 Kitex 支持。 本章小结如下: + - 首先,针对长连接模式分析了跨集群时上游源端口数问题,希望通过多路复用模式解决; - 其次,针对多路复用模式 + K8s Headless Service 模式的优雅升级,实测报错,分析定位了原因,Kitex 研发团队及时解决了相应问题; - 再次,针对多路复用模式 + K8s Service 模式下的优雅升级提出了方案,Kitex 团队完成了实现,迭代了一轮,测试通过; @@ -394,6 +408,7 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 ![huaxing34](/img/users/huaxingsec/huaxing34.png) 我们分析了环境差异: + - 生产环境是专线直连; - 测试环境,因为专线比较昂贵,机房之前通过公网访问,中间有个 NAT 设备。 @@ -403,10 +418,12 @@ Grafana 里我们配置了各类型服务调用耗时、错误码一体化看板 ![huaxing35](/img/users/huaxingsec/huaxing35.png) 本章小结如下: + - Rpc Timeout:Tontext Tanceled 问题分析和解决; - Rpc Error:Connection Reset 问题分析和解决。 ## 展望 + 未来我们计划把 Gin 更换为更高性能(QPS/时延)的 CloudWeGo-Hertz。因为我们 K 线服务的 Response Size 比较大(~202KiB),更换后 QPS 预计可达原先的 5 倍。 同时,为回馈开源社区,我们打算贡献 Tracing 基础库的代码到 Kitex-contrib/Tracer-opentracing。欢迎持续关注 CloudWeGo 项目,加入社区一起交流。 diff --git a/content/zh/cooperation/interface_testing.md b/content/zh/cooperation/interface_testing.md index 45e7087e39..c164ec026c 100644 --- a/content/zh/cooperation/interface_testing.md +++ b/content/zh/cooperation/interface_testing.md @@ -5,8 +5,8 @@ linkTitle: "接口测试平台" weight: 6 --- -> 2023 年 3 月,CloudWeGo Day 邀请了贪玩游戏、数美科技、字节跳动业务部门的一线架构师,为大家分享,在Java 转 go 场景下、企业高可用性挑战等场景下,如何通过 CloudWeGo 来落地微服务架构。本文为 **字节跳动研发工程师 陈佳庆** 分享内容。 -> +> 2023 年 3 月,CloudWeGo Day 邀请了贪玩游戏、数美科技、字节跳动业务部门的一线架构师,为大家分享,在Java 转 go 场景下、企业高可用性挑战等场景下,如何通过 CloudWeGo 来落地微服务架构。本文为 **字节跳动研发工程师 陈佳庆** 分享内容。 +> > **🔗 回放链接:** https://juejin.cn/live/cloudwegoday002 ## 嘉宾介绍 @@ -26,9 +26,9 @@ weight: 6 首先,来认识一下字节跳动微服务体系的特点: -- 服务基于 IDL 定义接口,服务之间通过 RPC 或者 HTTP 协议发起接口调用 -- RPC 协议不只是 Thrift 协议,还有 gRPC 和 Kitex Protobuf -- 服务端语言不只是 Golang,还有 Python、C++、Java 和 Rust +- 服务基于 IDL 定义接口,服务之间通过 RPC 或者 HTTP 协议发起接口调用 +- RPC 协议不只是 Thrift 协议,还有 gRPC 和 Kitex Protobuf +- 服务端语言不只是 Golang,还有 Python、C++、Java 和 Rust 下图是字节跳动微服务在内部环境的常见部署情况,从这张图中我们可以看到,在这个环境中部署了 3 个微服务,其中 service 1 是一个 HTTP 的服务,service 2 和 service 3 是一个 RPC 服务,它们都是基于 IDL 去定义它们的接口,服务之间的 RPC 通信通常会依赖下游的生成代码去进行。 @@ -40,12 +40,12 @@ weight: 6 ### 业务方做接口测试的痛点 -- **生态:** 业界和字节跳动内部都没有支持 Thrift 协议的接口测试平台 +- **生态:** 业界和字节跳动内部都没有支持 Thrift 协议的接口测试平台 -- **业务现状**: +- **业务现状**: - - 业务大多数 RPC 服务都是 Thrift 协议 - - RPC 接口测试效率低:基于 IDL 生成客户端代码,在单元测试代码里调用客户端发起 RPC 请求 + - 业务大多数 RPC 服务都是 Thrift 协议 + - RPC 接口测试效率低:基于 IDL 生成客户端代码,在单元测试代码里调用客户端发起 RPC 请求 首先,业务方大多数的 RPC 服务都是采用 Thrift 协议来实现的,少量采用 gRPC 和 Kitex Protobuffer 协议。业界当时已经有了Postman、grpcurl 这些好用的接口测试平台和工具类的产品,它们使用起来比较方便。然而,并没有一款接口测试平台能够比较好的支持 Thrift 协议。 @@ -57,9 +57,9 @@ weight: 6 有了这些业务现状和痛点,建设接口测试平台也成了一件自然而然的事情。平台的建设目标也很明确: -- 支持 Thrift、HTTP 协议 -- 适配字节跳动微服务体系 -- 产品功能对标业界同类产品 +- 支持 Thrift、HTTP 协议 +- 适配字节跳动微服务体系 +- 产品功能对标业界同类产品 接下来,我们可以了解接口测试平台1.0的实践,认识我们的接口测试平台是什么样子。 @@ -71,10 +71,10 @@ weight: 6 **接口测试平台的主要功能点** -- 支持 Thrift 和 HTTP 两种协议 -- 多 Tab、测试数据缓存、视图切换、读写超时配置等基础功能 -- 请求快照、备注收藏历史记录、分享请求等实用功能 -- 请求集合文件夹、时间/接口维度查看历史记录等组织功能 +- 支持 Thrift 和 HTTP 两种协议 +- 多 Tab、测试数据缓存、视图切换、读写超时配置等基础功能 +- 请求快照、备注收藏历史记录、分享请求等实用功能 +- 请求集合文件夹、时间/接口维度查看历史记录等组织功能 从产品界面图中可以看到,平台布局分为左、右两个区域。左侧区域可以展示用户的一个请求历史记录以及请求集合的一些数据,方便用户访问常用的请求数据。同时,右侧区域是一个请求编辑的区域,平台目前支持 Thrift 和 HTTP 两种协议类型。 @@ -94,9 +94,9 @@ weight: 6 下图是接口测试平台 1. 0 系统的流程图,核心思路是基于一段发送 RPC 请求的模板代码来生成可向被测服务发送 RPC 请求的可执行文件,进而通过调用可执行文件的命令来发起 RPC 调用。有三个关键节点: -- 事先定义好「发送 RPC 请求」的模版代码 -- 从 API 元数据中心拉取 IDL,执行 Kitex 命令生成被测服务的客户端代码 -- 将用户的请求入参以及客户端代码路径作为变量注入模版代码,生成可执行文件 +- 事先定义好「发送 RPC 请求」的模版代码 +- 从 API 元数据中心拉取 IDL,执行 Kitex 命令生成被测服务的客户端代码 +- 将用户的请求入参以及客户端代码路径作为变量注入模版代码,生成可执行文件 ![interface_testing5](/img/users/interface_testing/interface_testing5.png) @@ -131,8 +131,8 @@ weight: 6 目前**支持泛化调用的** **典型** **方案** **有** **:** -- gRPC 服务端反射 -- Kitex 客户端泛化调用 +- gRPC 服务端反射 +- Kitex 客户端泛化调用 先来了解一下 gRPC 服务端反射的实现方式。gRPC 框架提供了一种服务端反射的技术实现来支持实现泛化调用,像 grpcurl 这种工具就支持了 gRPC 的服务端反射。常规的交互流程,如下图所示。 @@ -214,10 +214,10 @@ Executor 收到的请求会携带有被测服务的名字、要测试的接口 ### 提升系统性能和稳定性 -- 降低接口测试请求的时延 -- 提高客户端缓存池的命中率 -- 探索 Serverless 方向 -- …… +- 降低接口测试请求的时延 +- 提高客户端缓存池的命中率 +- 探索 Serverless 方向 +- …… 持续地提升系统的稳定性和性能,是一个需要长期投入的方向。在这里可以给大家分享一下我们现在做的一些思考。 diff --git a/content/zh/cooperation/semir.md b/content/zh/cooperation/semir.md index 31b4ea1aab..942c5e2b08 100644 --- a/content/zh/cooperation/semir.md +++ b/content/zh/cooperation/semir.md @@ -103,6 +103,7 @@ Istio 基于 Enovy 的 xDS 协议扩展了其控制平面,每个 Pod 中放入 ![semir9](/img/users/semir/semir9.png) 在 Istio 中怎么部署我们的客户端或者服务端呢?有以下两种方式: + 1. 为命名空间开启自动注入:`kubectl label namespace default istio-injection=enabled`。注入之后会产生两个重要的容器,第一个是 Istio-proxy,负责流量拦截和流量代理,比如做流量转发;第二个是 Server-douyin,是负责开发的应用容器。 ![semir10](/img/users/semir/semir10.png) 2. 把 Go 代码打包的镜像部署到集群中: @@ -124,6 +125,7 @@ Istio 基于 Enovy 的 xDS 协议扩展了其控制平面,每个 Pod 中放入 ### Kitex 产生性能优势的原因 CloudWeGo 团队来森马做技术支持时讲到对自研网络库 Netpoll 做了一些性能优化,比如: + - 连接利用率; - 调度延迟优化; - 优化 I/O 调用; diff --git a/content/zh/cooperation/tanwan.md b/content/zh/cooperation/tanwan.md index 17f94befc3..68b9967707 100644 --- a/content/zh/cooperation/tanwan.md +++ b/content/zh/cooperation/tanwan.md @@ -5,11 +5,9 @@ linkTitle: "贪玩游戏" weight: 4 --- -> -> 2023 年 3 月,CloudWeGo Day 邀请了贪玩游戏、数美科技、字节跳动业务部门的一线架构师,为大家分享,在Java 转 go 场景下、企业高可用性挑战等场景下,如何通过 CloudWeGo 来落地微服务架构。本文为 **贪玩游戏技术经理 李华松** 分享内容。 -> +> 2023 年 3 月,CloudWeGo Day 邀请了贪玩游戏、数美科技、字节跳动业务部门的一线架构师,为大家分享,在Java 转 go 场景下、企业高可用性挑战等场景下,如何通过 CloudWeGo 来落地微服务架构。本文为 **贪玩游戏技术经理 李华松** 分享内容。 +> > **🔗 回放链接:** https://juejin.cn/live/cloudwegoday002 -> ## 嘉宾介绍 @@ -22,7 +20,6 @@ weight: 4 1. **CloudWeGo 架构的落地**。牛刀小试,积累经验,迅速扩展,修复问题。 1. **给相似业务的参考建议**。按团队思想、水平安排推进节奏,做好微服务拆分, 运维快学,善用外部资源,善用工具做好监控。 - ## 遇到的架构问题 ### 公司业务 @@ -42,17 +39,13 @@ weight: 4 - 场景1:**游戏大推** **。** 比如邀请了一个很受欢迎的代言人,在今日头条、抖音、广点通、微信朋友圈等各个媒体里大推广告时,如果我们的平台无法承受压力,可能会导致资金浪费。 - 场景2:**合作方集中推送游戏数据** **。** 因为我们是平台类应用,会关注用户各个方面的数据,合作方也会推送过来。合作方推送的数据通常是默认为 no problem,即合作方推送多少你都可以接多少。在这种情况下,如果我们的 php-fpm **处理能力**较低,合作方的观感可能会受到影响。 - 场景3:**合作方游戏更新大批量玩家验证 token、重登录**。游戏通常每两周更新一次,更新时如果程序重新启动,可能会导致游戏掉线并重新启动。如果有 token,则需要提交 token 进行验证,同时需要具备高并发能力以应对大量瞬时上线的请求。 - - 场景4:**接口被刷**。因为游戏中有一些生态,有些玩家会在游戏生态中找到存在或生存的方法,因此会储备大量账号。如果接口被刷,我们会有风控措施,但万一这些刷量的大量请求到达服务器时,我们也应该能够承受。 + - 场景4:**接口被刷**。因为游戏中有一些生态,有些玩家会在游戏生态中找到存在或生存的方法,因此会储备大量账号。如果接口被刷,我们会有风控措施,但万一这些刷量的大量请求到达服务器时,我们也应该能够承受。 1. **运维扩展时间成本高,不灵活。** -例如处理不当或不足,可能导致单台服务器出现问题。为了解决这个问题,我们需要不断地增加服务器数量,这也会带来时间成本。如果完成了以下三个步骤,通常需要7分钟,这可能会导致玩家流失。 - - 3分钟,创建ecs服务 - - 3分钟,部署环境+同步代码+基本测试 - - 1分钟,上线现网环境 + 例如处理不当或不足,可能导致单台服务器出现问题。为了解决这个问题,我们需要不断地增加服务器数量,这也会带来时间成本。如果完成了以下三个步骤,通常需要7分钟,这可能会导致玩家流失。- 3分钟,创建ecs服务 - 3分钟,部署环境+同步代码+基本测试 - 1分钟,上线现网环境 ### 语言架构的探索选型 - **原生 Go 实践与应用** **Golang** @@ -65,14 +58,13 @@ Golang 是一种注重高效和并发编程的编程语言,提供了内存安 媒体点击下发服务高峰时能达到6、7kQPS,单机 php-fpm 性能难以支撑这么高的并发量,只能通过不断增加服务器资源成本来解决。而 Go 在并发这块有出色的性能表现,能极大地节省资源成本。 -在接收到日志信号的过程中,如果我们使用 php-fpm 来进行记录,它可能会达到几百个 QPS。因此,需要部署数十台服务器才能支撑如此高的 QPS,我们认为这不应该耗费这么多资源。因此,我们将 Go 语言用于实现一个简单的替换,即使用原生的 Go 语言编写一个 HTTP 服务,将日志请求转发到 Go 中,并将这些日志写到指定的 channel 中,然后返回。channel 后边有一个定时器不断地将信道里的日志写到指定的地方。 +在接收到日志信号的过程中,如果我们使用 php-fpm 来进行记录,它可能会达到几百个 QPS。因此,需要部署数十台服务器才能支撑如此高的 QPS,我们认为这不应该耗费这么多资源。因此,我们将 Go 语言用于实现一个简单的替换,即使用原生的 Go 语言编写一个 HTTP 服务,将日志请求转发到 Go 中,并将这些日志写到指定的 channel 中,然后返回。channel 后边有一个定时器不断地将信道里的日志写到指定的地方。 **使用** 通过使用 net/http 标准库 快递搭建一个 http 服务器,下发的数据通过 Channel 操作实时写入日志文件,然后通过 filebeat 采集同步到 kafka 进行数据清洗,重构后单台8核16g内存的服务器可以扛住 **1w+ QPS**。 ![tanwan2](/img/users/tanwan/tanwan2.png) - **业务重构** @@ -136,7 +128,6 @@ Golang 是一种注重高效和并发编程的编程语言,提供了内存安 同时段 token 验证到失效了,要再次登录的请求量 - ### 语言架构的探索选型 ### 我们的选择 CloudWeGo @@ -152,7 +143,7 @@ Golang 是一种注重高效和并发编程的编程语言,提供了内存安 我们会根据我们的经验来评估他们之前是否做过类似场景的开发,并查看他们是否开源了相关内容。在这种情况下,我们发现了字节跳动开源了 CloudWeGo 框架。 -### **高性能的系列开源组件** +### **高性能的系列开源组件** 如果仅从普通框架的角度来看待它,一般认为上层建筑更为重要,但 CloudWeGo 会进行底层的优化,专注于打造高性能的框架和中间件。 @@ -160,7 +151,7 @@ Golang 是一种注重高效和并发编程的编程语言,提供了内存安 ![tanwan13](/img/users/tanwan/tanwan13.png) -### 快速开发,扩展性强 +### 快速开发,扩展性强 我们的诉求是,即可实现简易版单体应用开发,又可实现微服务架构拆分和高性能通信。 @@ -170,7 +161,7 @@ Golang 是一种注重高效和并发编程的编程语言,提供了内存安 ![tanwan14](/img/users/tanwan/tanwan14.png) -### 专业辅助,社区火热 +### 专业辅助,社区火热 此外,CloudWeGo 社区也很活跃。有专业技术人士指引辅导,且基本2周一次社区开发者例会。 @@ -198,7 +189,6 @@ Golang 是一种注重高效和并发编程的编程语言,提供了内存安 ![tanwan15](/img/users/tanwan/tanwan15.png) - **所用组件** 然后我们可以看一下我们用到的一些组件,例如微服务,必须具备服务注册、发现和配置等功能。 @@ -233,10 +223,8 @@ Golang 是一种注重高效和并发编程的编程语言,提供了内存安 ![tanwan17](/img/users/tanwan/tanwan17.png) - 这是一个 settingservice 的监控图,跑了一些 CPU、内存监控,就是运维关注的一般的基础资源的使用情况。 - ![tanwan18](/img/users/tanwan/tanwan18.png) 我们业务上可能会更加关心延延时,就是下边的图。 **P95、P50 平均值基本上在几十毫秒或者三十**。因为在 K8S 里面, 需要访问我们的一些阿里云服务,比如说数据库, Redis 这些的时候,它从里边到外边也是有一定的时延了。 @@ -263,26 +251,24 @@ Golang 是一种注重高效和并发编程的编程语言,提供了内存安 1. **Kitex 微服务 RPC** -- SettingService -- AccountService -- PayService ... 几十个 +- SettingService +- AccountService +- PayService ... 几十个 2. **Hertz 微服务 HTTP** -- ApisdkPassport -- ApiSdkLog -- WebApi ... 上十个 +- ApisdkPassport +- ApiSdkLog +- WebApi ... 上十个 当然,我们一直在持续推进做这件事。在这两个框架的支撑下,我们可以向其中塞入更多的业务。我们正在不断地向其中塞入更多的业务。如图所示是基本结构:Kitex 集成了一系列的微服务RPC,其中包含业务逻辑重心。对于前端来说,SDK 客户端或其它 HTTP 请求时,使用 Hertz 框架进行简单的接收和RPC调用后端处理逻辑,然后返回。这是我们SDK全面重构的一个实践,我们的团队实践后整体跑得都很稳定。 我们做的一部分事情的呈现就像下面的拓扑图,它是一张展示了我们的服务不断地调用的图。里面有很多服务,形成了一张类似网状的东西。当然,它是有迹可循的,如果一个请求发过来,它调用了几十个服务,那如果你要去排查一些东西,就需要用到链路追踪。 - ![tanwan23](/img/users/tanwan/tanwan23.png) Trace拓扑图 - **Tracing** 微服务架构在对比单架构模式上的性能方面有较大提升,但对应业务复杂度随之上升,出现排查问题难度大,周期长,系统性能瓶颈分析难。 链路追踪是一种用于解决微服务架构中分布式系统调用链路追踪和性能分析的技术。通过在每个服务中加入一些跟踪信息,可以记录请求在各个服务之间的传输路径和所经过的时间,从而形成一个完整的调用链路,协助我们快速定位和解决性能瓶颈问题,进一步优化系统性能。 @@ -301,7 +287,7 @@ Trace拓扑图 **技术支持** -还提供了全面的技术支持 ^_^ 专群对接、业内大神多、 跟进迅速、效果显著... +还提供了全面的技术支持 ^\_^ 专群对接、业内大神多、 跟进迅速、效果显著... 我们当时选这个框架的时候,CloudWeGo 有一个大群,我们进去提问就有专人对接,最后给我们拉一个专群,里边大神很多。基本上我们的 QPS 可能就几千、几万,CloudWeGo 处理的 QPS可能达到3亿、 10 亿级别,他们面对的场景会比我们更加高并发,更加多用户,更有经验。 @@ -344,7 +330,7 @@ SLB 后端被移除的瞬间,客户端压测直接通过 SLB 的 IP 访问服 我们使用链路追踪,分段细化加入 span 记录链路时间,分析每个 span 的耗时,找出耗时过长的 span,然后查看线上相关数据。 -- **找出问题:** +- **找出问题:** 1. 发现耗时都是在 SettingService 读取 oss 文件时 1. 猜测并发时自身的 dataMap 经常有锁住 @@ -353,8 +339,7 @@ SLB 后端被移除的瞬间,客户端压测直接通过 SLB 的 IP 访问服 ![tanwan28](/img/users/tanwan/tanwan28.png) - -- **问题优化** +- **问题优化** 1. 初步使用 gcache 优化,阻止多个协程并发读取同一文件 1. 根据 LRU 算法,区分冷热数据,按量使用 Goroutine 定时主动并行更新热点数据 @@ -375,29 +360,29 @@ SLB 后端被移除的瞬间,客户端压测直接通过 SLB 的 IP 访问服 1. **稳定性提升** -- **上限提升** **压测** **单** **Pod** **1c2g 400+** **qps** **。** 我们追求的是稳定性,即实现方式的上限提升,从而单台机器处理能力也更高了。现在,我们单台单个 Pod 可以测试出1核 2G 的内存,基本上可以测试到 400 个 QPS。在登录场景下,明显比php-fpm的处理效果要好。 -- **自动伸缩容。** 第二个是 K8S 这一块的自动伸缩容,这一块是 K8S 天生以来的好东西。它请求量大了,会自动扩多个Pod并调度起来,从而可承载的业务请求量更大。 -- **可承载的业务请求量更大** +- **上限提升** **压测** **单** **Pod** **1c2g 400+** **qps** **。** 我们追求的是稳定性,即实现方式的上限提升,从而单台机器处理能力也更高了。现在,我们单台单个 Pod 可以测试出1核 2G 的内存,基本上可以测试到 400 个 QPS。在登录场景下,明显比php-fpm的处理效果要好。 +- **自动伸缩容。** 第二个是 K8S 这一块的自动伸缩容,这一块是 K8S 天生以来的好东西。它请求量大了,会自动扩多个Pod并调度起来,从而可承载的业务请求量更大。 +- **可承载的业务请求量更大** 2. **CloudWeGo** **提高开发成效** 整体收益是使用 CloudWeGo 框架后,我们提高了开发效率、提升了性能可靠性、简化了部署流程,现在一键部署很方便。此外,我们还增加了业务弹性,可以往里面塞更多东西,从而降低成本,符合当前降本增效的主题,但需要不断地往里边塞更多业务。 -- 提升性能和可靠性 -- 提高开发效率 -- 简化部署和管理 -- 增加业务弹性 -- 降低IT成本 -- ...... +- 提升性能和可靠性 +- 提高开发效率 +- 简化部署和管理 +- 增加业务弹性 +- 降低IT成本 +- ...... 3. **团队能力提升** 我们的人员已经具备一定的技术水平,他们确实需要扩充自己的技术栈,丰富团队的技术能力。我们学习了 Go 语言,并与 CloudWeGo 一起成长,我们自己才能在行业抢占先机。我们的定位不同,所以最终的结果也会不同。我们整个团队可以应对更广泛的业务场景,因为以前可能只能处理 a 类业务,现在我们团队也可以处理b、c、d、e类业务。 -- 丰富队伍的技术栈 -- 强者 CloudWeGo 指引,自身更强 -- 可应对更宽广的业务场景 -- ... +- 丰富队伍的技术栈 +- 强者 CloudWeGo 指引,自身更强 +- 可应对更宽广的业务场景 +- ... 因此,我们用了 CloudWeGo 之后,整体收益还是比较不错的。 diff --git a/content/zh/css/docs.css b/content/zh/css/docs.css index f54ad8db1f..224a3cd1d6 100644 --- a/content/zh/css/docs.css +++ b/content/zh/css/docs.css @@ -62,11 +62,10 @@ color: #fff; } - .home-quote { font-weight: 300; margin: 25px 0 25px 0; - font-family: 'Lato', sans-serif; + font-family: "Lato", sans-serif; color: #fff; text-align: center; } @@ -114,7 +113,6 @@ text-align: center; } - .home-used-by-item img { max-width: 228px; max-height: 128px; @@ -165,7 +163,6 @@ } @media (min-width: 768px) { - .td-block-padding, .td-default main section { padding-top: 3rem; diff --git a/content/zh/docs/_index.md b/content/zh/docs/_index.md index 23d5d70ea6..44aacdcc94 100755 --- a/content/zh/docs/_index.md +++ b/content/zh/docs/_index.md @@ -1,4 +1,3 @@ - --- title: "文档" linkTitle: "文档" diff --git a/content/zh/docs/cwgo/_index.md b/content/zh/docs/cwgo/_index.md index 58b33f61bb..c6d31d28cf 100644 --- a/content/zh/docs/cwgo/_index.md +++ b/content/zh/docs/cwgo/_index.md @@ -1,10 +1,10 @@ --- -title: 'Cwgo' -linkTitle: 'Cwgo' +title: "Cwgo" +linkTitle: "Cwgo" weight: 5 Description: Cwgo 是 CloudWeGo All in one 代码生成工具,整合了各个组件的优势,以提高开发者的体验。 menu: main: weight: 5 - parent: '文档' + parent: "文档" --- diff --git a/content/zh/docs/cwgo/tutorials/_index.md b/content/zh/docs/cwgo/tutorials/_index.md index 5b4e5ea74f..0159d6233e 100644 --- a/content/zh/docs/cwgo/tutorials/_index.md +++ b/content/zh/docs/cwgo/tutorials/_index.md @@ -3,5 +3,4 @@ title: "指南" linkTitle: "指南" weight: 3 description: > - --- diff --git a/content/zh/docs/cwgo/tutorials/api-list/cautions.md b/content/zh/docs/cwgo/tutorials/api-list/cautions.md index 597d4c9432..7a7884a5b7 100644 --- a/content/zh/docs/cwgo/tutorials/api-list/cautions.md +++ b/content/zh/docs/cwgo/tutorials/api-list/cautions.md @@ -10,7 +10,7 @@ description: > ## 解析的项目代码注意事项 - `*server.Hertz`, `*route.Engine`, `*route.Group` 只能是 **局部变量** - + 即变量只能在该 **函数参数** 或 **函数内部** 中声明 - 调用 `Group()` 及 **路由注册函数** 中传入的 **relativePath** 必须是 **字符串字面量**,不能是 **变量** diff --git a/content/zh/docs/cwgo/tutorials/api-list/commands.md b/content/zh/docs/cwgo/tutorials/api-list/commands.md index dbccfe40f9..b37e6fad78 100644 --- a/content/zh/docs/cwgo/tutorials/api-list/commands.md +++ b/content/zh/docs/cwgo/tutorials/api-list/commands.md @@ -48,18 +48,19 @@ OPTIONS: ```json [ - { - "file_path":"/Users/bytedance/Projects/Personal/Golang/hz-example-thrift/biz/router/hello/example/hello.go", - "start_line":20, - "end_line":20, - "method":"GET", - "route_path":"/hello" - }, - { - "file_path":"/Users/bytedance/Projects/Personal/Golang/hz-example-thrift/router.go", - "start_line":12, - "end_line":12, - "method":"GET", - "route_path":"/ping"} + { + "file_path": "/Users/bytedance/Projects/Personal/Golang/hz-example-thrift/biz/router/hello/example/hello.go", + "start_line": 20, + "end_line": 20, + "method": "GET", + "route_path": "/hello" + }, + { + "file_path": "/Users/bytedance/Projects/Personal/Golang/hz-example-thrift/router.go", + "start_line": 12, + "end_line": 12, + "method": "GET", + "route_path": "/ping" + } ] ``` diff --git a/content/zh/docs/cwgo/tutorials/api-list/example.md b/content/zh/docs/cwgo/tutorials/api-list/example.md index c6b09c31b0..974d92e8a7 100644 --- a/content/zh/docs/cwgo/tutorials/api-list/example.md +++ b/content/zh/docs/cwgo/tutorials/api-list/example.md @@ -8,6 +8,7 @@ description: > ## 简单示例 以 `hz` 工具生成的项目为例: + > 生成步骤参考 [hz 使用(thrift)](/zh/docs/hertz/tutorials/toolkit/usage-thrift) 项目目录结构如下: @@ -66,7 +67,6 @@ func Register(r *server.Hertz) { 现在在项目根目录执行 `api-list` 命令 - `cwgo api-list` 或 `cwgo api-list --project_path .` 输出效果如下: diff --git a/content/zh/docs/cwgo/tutorials/client/command.md b/content/zh/docs/cwgo/tutorials/client/command.md index 09222495ac..580593d90a 100644 --- a/content/zh/docs/cwgo/tutorials/client/command.md +++ b/content/zh/docs/cwgo/tutorials/client/command.md @@ -14,10 +14,10 @@ NAME: cwgo client - generate RPC or HTTP client Examples: - # Generate RPC client code + # Generate RPC client code cwgo client --type RPC --idl {{path/to/IDL_file.thrift}} --service {{svc_name}} - - # Generate HTTP client code + + # Generate HTTP client code cwgo client --type HTTP --idl {{path/to/IDL_file.thrift}} --service {{svc_name}} diff --git a/content/zh/docs/cwgo/tutorials/client/example_pb.md b/content/zh/docs/cwgo/tutorials/client/example_pb.md index 1c7138de83..d9fb4f72b9 100644 --- a/content/zh/docs/cwgo/tutorials/client/example_pb.md +++ b/content/zh/docs/cwgo/tutorials/client/example_pb.md @@ -32,7 +32,7 @@ service HelloService { ### 执行命令 ->Note: 项目位于非 GOPATH 下必须指定 gomod,GOPATH 下默认以相对于 GOPATH 的路径作为名字,可不指定 gomod。 +> Note: 项目位于非 GOPATH 下必须指定 gomod,GOPATH 下默认以相对于 GOPATH 的路径作为名字,可不指定 gomod。 ```sh cwgo client --type RPC --idl hello.proto --service hellotest --module {{your_module_name}} -I . @@ -158,7 +158,7 @@ service HelloService { ### 执行命令 ->Note: 项目位于非 GOPATH 下必须指定 gomod,GOPATH 下默认以相对于 GOPATH 的路径作为名字,可不指定 gomod。 +> Note: 项目位于非 GOPATH 下必须指定 gomod,GOPATH 下默认以相对于 GOPATH 的路径作为名字,可不指定 gomod。 ```sh cwgo client --type HTTP --idl hello.proto --service hellotest --module {{your_module_name}} diff --git a/content/zh/docs/cwgo/tutorials/client/example_thrift.md b/content/zh/docs/cwgo/tutorials/client/example_thrift.md index 51c7ec17fe..62555dd5b7 100644 --- a/content/zh/docs/cwgo/tutorials/client/example_thrift.md +++ b/content/zh/docs/cwgo/tutorials/client/example_thrift.md @@ -30,7 +30,7 @@ service HelloService { ### 执行命令 ->Note: 项目位于非 GOPATH 下必须指定 gomod,GOPATH 下默认以相对于 GOPATH 的路径作为名字,可不指定 gomod。 +> Note: 项目位于非 GOPATH 下必须指定 gomod,GOPATH 下默认以相对于 GOPATH 的路径作为名字,可不指定 gomod。 ```sh cwgo client --type RPC --idl hello.thrift --service hellotest --module {{your_module_name}} @@ -88,7 +88,7 @@ service HelloService { ### 执行命令 ->Note: 项目位于非 GOPATH 下必须指定 gomod,GOPATH 下默认以相对于 GOPATH 的路径作为名字,可不指定 gomod。 +> Note: 项目位于非 GOPATH 下必须指定 gomod,GOPATH 下默认以相对于 GOPATH 的路径作为名字,可不指定 gomod。 ```sh cwgo client --type HTTP --idl hello.thrift --service hellotest --module {{your_module_name}} diff --git a/content/zh/docs/cwgo/tutorials/db/_index.md b/content/zh/docs/cwgo/tutorials/db/_index.md index f9f5d9d609..77e38c4cd7 100644 --- a/content/zh/docs/cwgo/tutorials/db/_index.md +++ b/content/zh/docs/cwgo/tutorials/db/_index.md @@ -57,9 +57,9 @@ OPTIONS: --model_pkg value 指定 model 的包名 --nullable 指定生成字段是否为指针当字段为 nullable,默认为 false --signable 指定字段是否检测整型列 unsigned 类型来调整生成相应的数据类型,默认为 false - --type_tag 指定字段是否生成 gorm 的 type tag,默认为 false + --type_tag 指定字段是否生成 gorm 的 type tag,默认为 false --index_tag 指定字段是否生成 gorm 的 index tag,默认为 false - --sql_dir value 指定一个sql文件或者目录(注意:当使用此参数时,--dsn参数失效) + --sql_dir value 指定一个sql文件或者目录(注意:当使用此参数时,--dsn参数失效) ``` ## 用法示例 diff --git a/content/zh/docs/cwgo/tutorials/doc/commands.md b/content/zh/docs/cwgo/tutorials/doc/commands.md index d78f82745d..7ec96ad6bf 100644 --- a/content/zh/docs/cwgo/tutorials/doc/commands.md +++ b/content/zh/docs/cwgo/tutorials/doc/commands.md @@ -37,24 +37,24 @@ OPTIONS: ## 详细参数 -- idl 指定生成代码所需使用的主 idl 路径 +- idl 指定生成代码所需使用的主 idl 路径 -- module/-mod 指定 go mod 名称,非 GOPATH 下必须指定,GOPATH 下默认以相对于 GOPATH 的路径作为名字 +- module/-mod 指定 go mod 名称,非 GOPATH 下必须指定,GOPATH 下默认以相对于 GOPATH 的路径作为名字 -- out_dir 指定代码输出目录, 默认为命令执行目录 +- out_dir 指定代码输出目录, 默认为命令执行目录 -- model_dir 指定 thriftgo 或 protoc 生成的 model 代码目录, 默认为 biz/doc/model +- model_dir 指定 thriftgo 或 protoc 生成的 model 代码目录, 默认为 biz/doc/model -- dao_dir 指定生成的 doc curd 代码目录, 默认为 biz/doc/dao +- dao_dir 指定生成的 doc curd 代码目录, 默认为 biz/doc/dao -- name 指定生成代码的文档型数据库名称, 默认为 mongodb, 目前仅支持 mongodb +- name 指定生成代码的文档型数据库名称, 默认为 mongodb, 目前仅支持 mongodb -- proto_search_path/-I 指定 idl 搜索目录, idl type 为 proto 时使用 +- proto_search_path/-I 指定 idl 搜索目录, idl type 为 proto 时使用 -- thriftgo/-t 透传给 thriftgo 的参数 +- thriftgo/-t 透传给 thriftgo 的参数 -- protoc/-p 透传给 protoc 的参数 +- protoc/-p 透传给 protoc 的参数 -- verbose 默认为 false, 指定为 true 后会输出更详细的日志内容 +- verbose 默认为 false, 指定为 true 后会输出更详细的日志内容 -- help/-h 帮助命令 +- help/-h 帮助命令 diff --git a/content/zh/docs/cwgo/tutorials/doc/example_thrift.md b/content/zh/docs/cwgo/tutorials/doc/example_thrift.md index b876041578..0817f600b0 100644 --- a/content/zh/docs/cwgo/tutorials/doc/example_thrift.md +++ b/content/zh/docs/cwgo/tutorials/doc/example_thrift.md @@ -7,7 +7,7 @@ description: > ## 简单示例 -### 创建 video.thrift +### 创建 video.thrift ```thrift namespace go video @@ -99,5 +99,3 @@ cwgo doc --idl user.thrift --module {your module name} ### 生成代码 生成代码的目录结构参考[生成代码的结构](/zh/docs/cwgo/tutorials/doc/layout/)。 - - diff --git a/content/zh/docs/cwgo/tutorials/doc/layout.md b/content/zh/docs/cwgo/tutorials/doc/layout.md index b4821142e3..5846bc9aa8 100644 --- a/content/zh/docs/cwgo/tutorials/doc/layout.md +++ b/content/zh/docs/cwgo/tutorials/doc/layout.md @@ -9,8 +9,8 @@ description: > > biz/doc/dao/{struct name}:存放 mongodb curd 代码,生成位置可通过 --dao_dir 修改 > -> - {struct name}_repo.go 函数接口文件 -> - {struct name}_repo_mongo.go 接口实现及具体 curd 代码 +> - {struct name}\_repo.go 函数接口文件 +> - {struct name}\_repo_mongo.go 接口实现及具体 curd 代码 > > biz/doc/model:thriftgo 或 protoc 生成的代码,Mongodb 集合对应的 go struct 位于此处,生成位置可通过 --model_dir 修改 diff --git a/content/zh/docs/cwgo/tutorials/doc/usage_rule.md b/content/zh/docs/cwgo/tutorials/doc/usage_rule.md index 0ad270f39d..9ac8aaeaa6 100644 --- a/content/zh/docs/cwgo/tutorials/doc/usage_rule.md +++ b/content/zh/docs/cwgo/tutorials/doc/usage_rule.md @@ -68,6 +68,7 @@ message 和各字段采用**大驼峰命名方式**或**蛇形命名方式**皆 ## 函数定义规则 函数名采用**驼峰式命名**,**首字母大写**,且第一个单词必须是如下之一: + - **Insert** - **Find** - **Update** @@ -102,15 +103,15 @@ message 和各字段采用**大驼峰命名方式**或**蛇形命名方式**皆 - **字段名**:go 中对应的结构体字段名称 - 若存在结构体嵌套情况,则字段名格式为:{子结构体在父结构体中的字段名}{子结构体中的具体字段名},例如 User 嵌套 Video,想要查找 Video 的 Id 字段,则为:VideoId + 若存在结构体嵌套情况,则字段名格式为:{子结构体在父结构体中的字段名}{子结构体中的具体字段名},例如 User 嵌套 Video,想要查找 Video 的 Id 字段,则为:VideoId - **排序分页等操作** -| 格式 | 描述 | 示例 | -|-------------------------------|---------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------| +| 格式 | 描述 | 示例 | +| -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | | **Orderby**{thrift 字段名123...} | 默认针对字段升序,若某个字段有降序的需求,在字段后加 Desc(只作用于单个字段,若有多个降序字段的需求,需要在每一个字段后面都跟 Desc),例 OrderbyName(升) AgeDesc(降) **入参不传值** | `FindUsernameOrderbyIdUsernameSkipLimitAll`(含两个字段 "id","Username") | -| **Skip** | 跳过文档数量 **入参传整数** | `FindUsernameOrderbyIdUsernameSkipLimitAll`(跳过文档) | -| **Limit** | 限制查询文档数量 **单实体操作不支持,入参传整数** | `FindUsernameOrderbyIdUsernameSkipLimitAll`(限制查询文档数量) | +| **Skip** | 跳过文档数量 **入参传整数** | `FindUsernameOrderbyIdUsernameSkipLimitAll`(跳过文档) | +| **Limit** | 限制查询文档数量 **单实体操作不支持,入参传整数** | `FindUsernameOrderbyIdUsernameSkipLimitAll`(限制查询文档数量) | - **查询条件** @@ -122,22 +123,22 @@ message 和各字段采用**大驼峰命名方式**或**蛇形命名方式**皆 - **比较条件**: -| **关键词** | **含义** | **入参值** | - |:---------------------|:------------------|:--------| -| **Equal** | 等于 | 该字段值 | -| **NotEqual** | 不等于 | 该字段值 | -| **LessThan** | 小于 | 该字段值 | -| **LessThanEqual** | 小于等于 | 该字段值 | -| **GreaterThan** | 大于 | 该字段值 | -| **GreaterThanEqual** | 大于等于 | 该字段值 | -| **Between** | [a,b] | 左右端点值 | -| **NotBetween** | b | 左右端点值 | -| **In** | 字段值在切片范围内 | 切片 | -| **NotIn** | 字段值不在切片范围内 | 切片 | -| **True** | 字段值是否为 true | - | -| **False** | 字段值是否为 false | - | -| **Exists** | 指定字段存在的文档 | - | -| **NotExists** | 指定字段不存在的文档 | - | +| **关键词** | **含义** | **入参值** | +| :------------------- | :------------------- | :--------- | +| **Equal** | 等于 | 该字段值 | +| **NotEqual** | 不等于 | 该字段值 | +| **LessThan** | 小于 | 该字段值 | +| **LessThanEqual** | 小于等于 | 该字段值 | +| **GreaterThan** | 大于 | 该字段值 | +| **GreaterThanEqual** | 大于等于 | 该字段值 | +| **Between** | [a,b] | 左右端点值 | +| **NotBetween** | b | 左右端点值 | +| **In** | 字段值在切片范围内 | 切片 | +| **NotIn** | 字段值不在切片范围内 | 切片 | +| **True** | 字段值是否为 true | - | +| **False** | 字段值是否为 false | - | +| **Exists** | 指定字段存在的文档 | - | +| **NotExists** | 指定字段不存在的文档 | - | ### Update @@ -221,7 +222,8 @@ Update 操作以更新对象的角度分为两种: ## 关键字 ->在命名结构体字段时,请勿包含如下关键字: +> 在命名结构体字段时,请勿包含如下关键字: + - **Insert** - **Find** - **Update** diff --git a/content/zh/docs/cwgo/tutorials/server/_index.md b/content/zh/docs/cwgo/tutorials/server/_index.md index 5c55637014..63f69ae104 100644 --- a/content/zh/docs/cwgo/tutorials/server/_index.md +++ b/content/zh/docs/cwgo/tutorials/server/_index.md @@ -10,4 +10,3 @@ cwgo 工具支持通过 IDL(thrift/protobuf) 生成 HTTP Server 或 RPC Server cwgo 默认提供了 MVC Template 生成 Server 代码,[RPC Tpl](https://github.com/cloudwego/cwgo/tree/main/tpl/kitex/server/standard),[HTTP Tpl](https://github.com/cloudwego/cwgo/tree/main/tpl/hertz/standard)。若默认模板不满足用户的需求,可参考[模板拓展](/zh/docs/cwgo/tutorials/templete-extension/)自定义自己的模板。 cwgo Server 支持在一个端口同时启用 HTTP 服务和 RPC 服务,详见[hex用法示例](https://github.com/cloudwego/hertz-examples/tree/main/hex)。 - diff --git a/content/zh/docs/cwgo/tutorials/server/command.md b/content/zh/docs/cwgo/tutorials/server/command.md index 7668625380..ff42ebe849 100644 --- a/content/zh/docs/cwgo/tutorials/server/command.md +++ b/content/zh/docs/cwgo/tutorials/server/command.md @@ -14,10 +14,10 @@ NAME: cwgo server - generate RPC or HTTP server Examples: - # Generate RPC server code + # Generate RPC server code cwgo server --type RPC --idl {{path/to/IDL_file.thrift}} --service {{svc_name}} - # Generate HTTP server code + # Generate HTTP server code cwgo server --type HTTP --idl {{path/to/IDL_file.thrift}} --service {{svc_name}} diff --git a/content/zh/docs/cwgo/tutorials/server/example_pb.md b/content/zh/docs/cwgo/tutorials/server/example_pb.md index 21e3b4c971..1bad84ef3e 100644 --- a/content/zh/docs/cwgo/tutorials/server/example_pb.md +++ b/content/zh/docs/cwgo/tutorials/server/example_pb.md @@ -32,7 +32,7 @@ service HelloService { ### 执行命令 ->Note: 项目位于非 GOPATH 下必须指定 gomod,GOPATH 下默认以相对于 GOPATH 的路径作为名字,可不指定 gomod。 +> Note: 项目位于非 GOPATH 下必须指定 gomod,GOPATH 下默认以相对于 GOPATH 的路径作为名字,可不指定 gomod。 ```sh cwgo server --type RPC --idl hello.proto --service hellotest --module {{your_module_name}} -I . @@ -158,7 +158,7 @@ service HelloService { ### 执行命令 ->Note: 项目位于非 GOPATH 下必须指定 gomod,GOPATH 下默认以相对于 GOPATH 的路径作为名字,可不指定 gomod。 +> Note: 项目位于非 GOPATH 下必须指定 gomod,GOPATH 下默认以相对于 GOPATH 的路径作为名字,可不指定 gomod。 ```sh cwgo server --type HTTP --idl hello.proto --service hellotest --module {{your_module_name}} diff --git a/content/zh/docs/cwgo/tutorials/server/example_thrift.md b/content/zh/docs/cwgo/tutorials/server/example_thrift.md index a112f1a29d..b91d195130 100644 --- a/content/zh/docs/cwgo/tutorials/server/example_thrift.md +++ b/content/zh/docs/cwgo/tutorials/server/example_thrift.md @@ -28,7 +28,7 @@ service HelloService { ### 执行命令 ->Note: 项目位于非 GOPATH 下必须指定 gomod,GOPATH 下默认以相对于 GOPATH 的路径作为名字,可不指定 gomod。 +> Note: 项目位于非 GOPATH 下必须指定 gomod,GOPATH 下默认以相对于 GOPATH 的路径作为名字,可不指定 gomod。 ```sh cwgo server --type RPC --idl hello.thrift --service hellotest --module {{your_module_name}} @@ -66,7 +66,7 @@ service HelloService { ### 执行命令 ->Note: 项目位于非 GOPATH 下必须指定 gomod,GOPATH 下默认以相对于 GOPATH 的路径作为名字,可不指定 gomod。 +> Note: 项目位于非 GOPATH 下必须指定 gomod,GOPATH 下默认以相对于 GOPATH 的路径作为名字,可不指定 gomod。 ```sh cwgo server --type HTTP --idl hello.thrift --service hellotest --module {{your_module_name}} diff --git a/content/zh/docs/cwgo/tutorials/templete-extension/_index.md b/content/zh/docs/cwgo/tutorials/templete-extension/_index.md index 0b8d0bf6e4..34a3f856ab 100644 --- a/content/zh/docs/cwgo/tutorials/templete-extension/_index.md +++ b/content/zh/docs/cwgo/tutorials/templete-extension/_index.md @@ -40,7 +40,7 @@ cwgo server -type RPC -service {service name} -idl {idl path} -template git@git ## RPC 1. 模板文件通过包含 yaml 文件的文件夹传递,该文件夹下的所有 yaml 文件都会被渲染,模版解析失败会直接退出。请注意是否存在未知的隐藏文件。 - + Yaml 文件定义如下: ```yaml @@ -54,7 +54,7 @@ cwgo server -type RPC -service {service name} -idl {idl path} -template git@git loop_method: true # 是否开启循环渲染 body: template content # 模板内容 ``` - + 2. `extensions.yaml` 为特定文件,该文件的内容为[扩展 Service 代码](/zh/docs/kitex/tutorials/code-gen/template_extension/)的配置文件。请注意文件命名冲突问题。 3. 模板使用的数据为 PackageInfo,认为这部分内包含所有的元数据,如 methodInfo 等,用户只需要传递模板文件即可,模板内的数据为 PackageInfo 数据。PackageInfo 内常用的内容见[附录](#附录)。 diff --git a/content/zh/docs/hertz/_index.md b/content/zh/docs/hertz/_index.md index a9f3d526b5..7bc67c9c24 100644 --- a/content/zh/docs/hertz/_index.md +++ b/content/zh/docs/hertz/_index.md @@ -1,10 +1,10 @@ --- -title: 'Hertz' -linkTitle: 'Hertz' +title: "Hertz" +linkTitle: "Hertz" weight: 2 Description: Hertz [həːts] 是一个 Golang 微服务 HTTP 框架,具有高易用性、高性能、高扩展性等特点。如果对微服务性能有要求,又希望框架能够充分满足内部的可定制化需求,Hertz 会是一个不错的选择。 menu: main: weight: 2 - parent: '文档' + parent: "文档" --- diff --git a/content/zh/docs/hertz/faq/_index.md b/content/zh/docs/hertz/faq/_index.md index ea178afa06..322fdb51eb 100644 --- a/content/zh/docs/hertz/faq/_index.md +++ b/content/zh/docs/hertz/faq/_index.md @@ -4,12 +4,12 @@ linkTitle: "常见问题" weight: 4 keywords: ["内存使用率", "常见错误码", "上下文使用", "精度丢失问题"] description: "Hertz 常见问题解答。" - --- ## 内存使用率高 ### 客户端不规范使用没有关连接 + 如果 Client 侧发起大量连接而不关闭的话,极端情况下会有较大的资源浪费,随着时间的增长,可能会造成内存使用率高的问题。 **解决办法** @@ -17,6 +17,7 @@ description: "Hertz 常见问题解答。" 合理配置 `idleTimeout`,超时后 Hertz Server 会把连接关掉保证 Server 侧的稳定性。默认配置为3分钟。 ### 超大请求/响应 + 1. 如果请求和响应非常大,并且没有使用一些其他发送模式如 stream、chunk 时,数据会全部进入内存,给内存造成较大压力。 2. netpoll 网络库下的流式为假流式。由于 netpoll 使用 LT 触发模式,当数据到达时,会触发 netpoll 读取数据;在接口设计上,也因此没有实现 `Reader` 接口。为了实现流式的能力,Hertz 将 netpoll 封装为 Reader,但其本身数据仍然不可控的进入了内存,所以在超大流式请求的情况下,可能会造成内存压力。 @@ -29,6 +30,7 @@ description: "Hertz 常见问题解答。" 如果框架报以下的错误码,可以按照可能原因进行排查。如果出现非以下错误码,则不是框架打出来的,需要由使用方定位一下是否自行设置或者由某些中间件设置了错误码。 ### 404 + 1. 访问到了错误的端口上了,常见访问到了 debug 端口 1. 解决方案:区分框架服务的监听端口和 debug server 的监听端口,默认:8888 2. 未匹配到路由 @@ -36,9 +38,11 @@ description: "Hertz 常见问题解答。" 2. 查看访问方法是否正确 ### 417 + server 在执行完自定义的 `ContinueHandler` 之后返回 `false`(server 主动拒绝掉 100 Continue 后续的 body)。 ### 500 + 1. 中间件或者 `handlerFunc` 中抛 panic 1. 解决方案:panic 栈信息定位具体问题 2. fs 场景 path 携带 `/../`,可能出现访问预期之外的文件,server 端 app log 中伴随错误日志:`cannot serve path with '/../' at position %d due to security reasons: %q`。 @@ -47,13 +51,16 @@ server 在执行完自定义的 `ContinueHandler` 之后返回 `false`(server ## 上下文使用指南 ### 说明 + Hertz 在 `HandlerFunc` 设计上,同时提供了一个标准 `context.Context` 和一个请求上下文作为函数的入参。 `handler/middleware` 函数签名为: + ```go type HandlerFunc func(c context.Context, ctx *RequestContext) ``` ### 元数据存储方面 + 两个上下文都有储值能力,使用时具体选择哪一个的简单依据:所储存值的生命周期和所选择的上下文要匹配。 **具体细节** @@ -72,7 +79,7 @@ type HandlerFunc func(c context.Context, ctx *RequestContext) ```javascript var s = '{"x":6855337641038665531}'; var obj = JSON.parse(s); -alert (obj.x); +alert(obj.x); // Output 6855337641038666000 ``` @@ -146,4 +153,3 @@ func main() { } ``` - diff --git a/content/zh/docs/hertz/getting-started/_index.md b/content/zh/docs/hertz/getting-started/_index.md index e89c29e65c..4d830b0b2b 100644 --- a/content/zh/docs/hertz/getting-started/_index.md +++ b/content/zh/docs/hertz/getting-started/_index.md @@ -112,16 +112,19 @@ hz 是 Hertz 框架提供的一个用于生成代码的命令行工具,可以 1. 在当前目录下创建 hertz_demo 文件夹,进入该目录中。 2. 生成代码 - - 直接使用 `hz new`,若当前不在 `GOPATH`,需要添加 `-module` 或者 `-mod` flag 指定一个自定义的模块名称。详细参考[这里](/zh/docs/hertz/tutorials/toolkit/usage/)。 - - 通过指定已经定义好的 idl 文件进行代码生成,例如 `hz new -idl hello.thrift`。 - ```thrift - namespace go hello.world - - service HelloService { - string Hello(1: string name); - } - ``` - 执行完毕后, 会在当前目录下生成 Hertz 项目的脚手架, 自带一个 `ping` 接口用于测试。 + +- 直接使用 `hz new`,若当前不在 `GOPATH`,需要添加 `-module` 或者 `-mod` flag 指定一个自定义的模块名称。详细参考[这里](/zh/docs/hertz/tutorials/toolkit/usage/)。 +- 通过指定已经定义好的 idl 文件进行代码生成,例如 `hz new -idl hello.thrift`。 + + ```thrift + namespace go hello.world + + service HelloService { + string Hello(1: string name); + } + ``` + + 执行完毕后, 会在当前目录下生成 Hertz 项目的脚手架, 自带一个 `ping` 接口用于测试。 3. 整理 & 拉取依赖。 @@ -180,4 +183,4 @@ hz update -idl hello.thrift ## 更多示例 -参考:[代码示例](/zh/docs/hertz/tutorials/example/) \ No newline at end of file +参考:[代码示例](/zh/docs/hertz/tutorials/example/) diff --git a/content/zh/docs/hertz/overview/_index.md b/content/zh/docs/hertz/overview/_index.md index 76136c4df4..807f67497a 100644 --- a/content/zh/docs/hertz/overview/_index.md +++ b/content/zh/docs/hertz/overview/_index.md @@ -4,10 +4,8 @@ linkTitle: "概览" weight: 1 keywords: ["HTTP", "Hertz", "架构设计", "框架特点", "框架性能"] description: "Hertz 架构设计、框架特点、框架性能。" - --- - ## CloudWeGo-Hertz Hertz[həːts] 是一个 Golang 微服务 HTTP 框架,在设计之初参考了其他开源框架 [fasthttp](https://github.com/valyala/fasthttp)、[gin](https://github.com/gin-gonic/gin)、[echo](https://github.com/labstack/echo) 的优势, @@ -15,9 +13,11 @@ Hertz[həːts] 是一个 Golang 微服务 HTTP 框架,在设计之初参考了 如今越来越多的微服务选择使用 Golang,如果对微服务性能有要求,又希望框架能够充分满足内部的可定制化需求,Hertz 会是一个不错的选择。 ## 架构设计 + ![HERTZ](/img/docs/hertz.png) ## 框架特点 + - 高易用性 在开发过程中,快速写出来正确的代码往往是更重要的。因此,在 Hertz 在迭代过程中,积极听取用户意见,持续打磨框架,希望为用户提供一个更好的使用体验,帮助用户更快的写出正确的代码。 @@ -49,16 +49,19 @@ Hertz[həːts] 是一个 Golang 微服务 HTTP 框架,在设计之初参考了 Hertz 实现了 Netpoll 和 Golang 原生网络库 间按需切换能力,用户可以针对不同的场景选择合适的网络库,同时也支持以插件的方式为 Hertz 扩展网络库实现。 ## 框架性能 + 性能测试只能提供相对参考,工业场景下,有诸多因素可以影响实际的性能表现。 我们提供了 [hertz-benchmark](https://github.com/cloudwego/hertz-benchmark) 项目用来长期追踪和比较 Hertz 与其他框架在不同情况下的性能数据以供参考。 ## 相关项目 + - [Netpoll](https://github.com/cloudwego/netpoll): 自研高性能网络库,Hertz 默认集成 - [Hertz-Contrib](https://github.com/hertz-contrib): Hertz 扩展仓库,提供中间件、tracer 等能力 - [Example](https://github.com/cloudwego/hertz-examples): Hertz 使用例子 ## 相关文章 + - [Hertz 支持 QUIC & HTTP/3](/zh/blog/2023/08/02/hertz-支持-quic-http/3/) - [HTTP 框架 Hertz 实践入门:性能测试指南](/zh/blog/2023/02/24/http-框架-hertz-实践入门性能测试指南/) - [助力字节降本增效,大规模企业级 HTTP 框架 Hertz 设计实践](/zh/blog/2022/09/27/助力字节降本增效大规模企业级-http-框架-hertz-设计实践/) diff --git a/content/zh/docs/hertz/reference/_index.md b/content/zh/docs/hertz/reference/_index.md index 8713142cdd..7b09c6b549 100644 --- a/content/zh/docs/hertz/reference/_index.md +++ b/content/zh/docs/hertz/reference/_index.md @@ -4,5 +4,4 @@ linkTitle: "参考" weight: 5 keywords: ["配置说明", "版本说明"] description: "Hertz 相关参考。" - --- diff --git a/content/zh/docs/hertz/reference/config.md b/content/zh/docs/hertz/reference/config.md index d18d2c57cc..eacb1f5c5d 100644 --- a/content/zh/docs/hertz/reference/config.md +++ b/content/zh/docs/hertz/reference/config.md @@ -4,7 +4,6 @@ linkTitle: "配置说明" weight: 1 keywords: ["配置说明"] description: "Hertz 配置说明。" - --- ## Server @@ -22,51 +21,51 @@ func main() { } ``` -| 配置名称 | 类型 | 说明 | -| :---- |:-------------------------------------------------------------| :---- | -| WithTransport | network.NewTransporter | 更换底层 transport,默认值:netpoll.NewTransporter | -| WithHostPorts | string | 指定监听的地址和端口 | -| WithKeepAliveTimeout | time.Duration | tcp 长连接保活时间,一般情况下不用修改,更应该关注 idleTimeout。默认值:1min | -| WithReadTimeout | time.Duration | 底层读取数据超时时间。默认值:3min | -| WithIdleTimeout | time.Duration | 长连接请求链接空闲超时时间。默认值:3min | -| WithMaxRequestBodySize | int | 配置最大的请求体大小,默认 4M(4M 对应的填的值是 4\*1024\*1024) | -| WithRedirectTrailingSlash | bool | 自动根据末尾的 / 转发,例如:如果 router 只有 /foo/,那么 /foo 会重定向到 /foo/ ;如果只有 /foo,那么 /foo/ 会重定向到 /foo。默认开启 | -| WithRemoveExtraSlash | bool | RemoveExtraSlash 当有额外的 / 时也可以当作参数。如:user/:name,如果开启该选项 user//xiaoming 也可匹配上参数。默认关闭 | -| WithUnescapePathValues | bool | 如果开启,请求路径会被自动转义(eg. '%2F' -> '/')。如果 UseRawPath 为 false(默认情况),则 UnescapePathValues 实际上为 true,因为 .URI().Path() 将被使用,它已经是转义后的。设置该参数为 false,需要配合 WithUseRawPath(true)。默认开启 (true) | -| WithUseRawPath | bool | 如果开启,会使用原始 path 进行路由匹配。默认关闭 | -| WithHandleMethodNotAllowed | bool | 如果开启,当当前路径不能被匹配上时,server 会去检查其他方法是否注册了当前路径的路由,如果存在则会响应"Method Not Allowed",并返回状态码 405; 如果没有,则会用 NotFound 的 handler 进行处理。默认关闭 | -| WithDisablePreParseMultipartForm | bool | 如果开启,则不会预处理 multipart form。可以通过 ctx.Request.Body() 获取到 body 后由用户处理。默认关闭 | -| WithStreamBody | bool | 如果开启,则会使用流式处理 body。默认关闭 | -| WithNetwork | string | 设置网络协议,可选:tcp,udp,unix(unix domain socket),默认为 tcp | -| ContinueHandler | func(header *RequestHeader) bool | 在接收到 Expect 100 Continue 头之后调用 ContinueHandler。使用 ContinueHandler,服务器可以决定是否根据标头读取可能很大的请求正文 | -| PanicHandler | HandlerFunc | 处理 panic,用来生成错误页面并返回 500 | -| NotFound | HandlerFunc | 当路由匹配不上时被调用的 handler | -| WithExitWaitTime | time.Duration | 设置优雅退出时间。Server 会停止建立新的连接,并对关闭后的每一个请求设置 Connection: Close 的 header,当到达设定的时间关闭 Server。当所有连接已经关闭时,Server 可以提前关闭。默认 5s | -| WithTLS | tls.Config | 配置 server tls 能力 | -| WithListenConfig | net.ListenConfig | 设置监听器配置,可用于设置是否允许 reuse port 等 | -| WithALPN | bool | 是否开启 ALPN。默认关闭 | -| WithTracer | tracer.Tracer | 注入 tracer 实现,如不注入 Tracer 实现,默认关闭 | -| WithTraceLevel | stats.Level | 设置 trace level,默认 LevelDetailed | -| WithWriteTimeout | time.Duration | 写入数据超时时间,默认值:无限长 | -| WithRedirectFixedPath | bool | 如果开启,当当前请求路径不能匹配上时,server 会尝试修复请求路径并重新进行匹配,如果成功匹配并且为 GET 请求则会返回状态码 301 进行重定向,其他请求方式返回 308 进行重定向。默认关闭 | -| WithBasePath | string | 设置基本路径,前缀和后缀必须为 `/`。默认为 `/` | -| WithMaxKeepBodySize | int | 设置回收时保留的请求体和响应体的最大大小。单位:字节。默认值:4 * 1024 * 1024 | -| WithGetOnly | bool | 如果开启则只接受 GET 请求。默认关闭 | -| WithKeepAlive | bool | 如果开启则使用 HTTP 长连接。默认开启 | -| WithAltTransport | network.NewTransporter | 设置备用 transport。默认值:netpoll.NewTransporter | -| WithH2C | bool | 设置是否开启 H2C。默认关闭 | -| WithReadBufferSize | int | 设置读缓冲区大小,同时限制 HTTP header 大小。默认值:4 * 1024 | -| WithRegistry | registry.Registry, *registry.Info | 设置注册中心配置,服务注册信息。默认值:registry.NoopRegistry, nil | -| WithAutoReloadRender | bool, time.Duration | 设置自动重载渲染配置。默认值:false, 0 | -| WithDisablePrintRoute | bool | 设置是否禁用 debugPrintRoute。默认不禁用 | -| WithOnAccept | func(conn net.Conn) context.Context | 设置在 netpoll 中当一个连接被接受但不能接收数据时的回调函数,在 go net 中在转换 TLS 连接之前被调用。默认值:nil | -| WithOnConnect | func(ctx context.Context, conn network.Conn) context.Context | 设置 onConnect 函数。它可以接收来自 netpoll 连接的数据。在 go net 中,它将在转换 TLS 连接后被调用。默认值:nil | -| WithDisableHeaderNamesNormalizing| bool |设置是否禁用 Request 和 Response Header 名字的规范化 (首字母和破折号后第一个字母大写)| +| 配置名称 | 类型 | 说明 | +| :-------------------------------- | :----------------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| WithTransport | network.NewTransporter | 更换底层 transport,默认值:netpoll.NewTransporter | +| WithHostPorts | string | 指定监听的地址和端口 | +| WithKeepAliveTimeout | time.Duration | tcp 长连接保活时间,一般情况下不用修改,更应该关注 idleTimeout。默认值:1min | +| WithReadTimeout | time.Duration | 底层读取数据超时时间。默认值:3min | +| WithIdleTimeout | time.Duration | 长连接请求链接空闲超时时间。默认值:3min | +| WithMaxRequestBodySize | int | 配置最大的请求体大小,默认 4M(4M 对应的填的值是 4\*1024\*1024) | +| WithRedirectTrailingSlash | bool | 自动根据末尾的 / 转发,例如:如果 router 只有 /foo/,那么 /foo 会重定向到 /foo/ ;如果只有 /foo,那么 /foo/ 会重定向到 /foo。默认开启 | +| WithRemoveExtraSlash | bool | RemoveExtraSlash 当有额外的 / 时也可以当作参数。如:user/:name,如果开启该选项 user//xiaoming 也可匹配上参数。默认关闭 | +| WithUnescapePathValues | bool | 如果开启,请求路径会被自动转义(eg. '%2F' -> '/')。如果 UseRawPath 为 false(默认情况),则 UnescapePathValues 实际上为 true,因为 .URI().Path() 将被使用,它已经是转义后的。设置该参数为 false,需要配合 WithUseRawPath(true)。默认开启 (true) | +| WithUseRawPath | bool | 如果开启,会使用原始 path 进行路由匹配。默认关闭 | +| WithHandleMethodNotAllowed | bool | 如果开启,当当前路径不能被匹配上时,server 会去检查其他方法是否注册了当前路径的路由,如果存在则会响应"Method Not Allowed",并返回状态码 405; 如果没有,则会用 NotFound 的 handler 进行处理。默认关闭 | +| WithDisablePreParseMultipartForm | bool | 如果开启,则不会预处理 multipart form。可以通过 ctx.Request.Body() 获取到 body 后由用户处理。默认关闭 | +| WithStreamBody | bool | 如果开启,则会使用流式处理 body。默认关闭 | +| WithNetwork | string | 设置网络协议,可选:tcp,udp,unix(unix domain socket),默认为 tcp | +| ContinueHandler | func(header \*RequestHeader) bool | 在接收到 Expect 100 Continue 头之后调用 ContinueHandler。使用 ContinueHandler,服务器可以决定是否根据标头读取可能很大的请求正文 | +| PanicHandler | HandlerFunc | 处理 panic,用来生成错误页面并返回 500 | +| NotFound | HandlerFunc | 当路由匹配不上时被调用的 handler | +| WithExitWaitTime | time.Duration | 设置优雅退出时间。Server 会停止建立新的连接,并对关闭后的每一个请求设置 Connection: Close 的 header,当到达设定的时间关闭 Server。当所有连接已经关闭时,Server 可以提前关闭。默认 5s | +| WithTLS | tls.Config | 配置 server tls 能力 | +| WithListenConfig | net.ListenConfig | 设置监听器配置,可用于设置是否允许 reuse port 等 | +| WithALPN | bool | 是否开启 ALPN。默认关闭 | +| WithTracer | tracer.Tracer | 注入 tracer 实现,如不注入 Tracer 实现,默认关闭 | +| WithTraceLevel | stats.Level | 设置 trace level,默认 LevelDetailed | +| WithWriteTimeout | time.Duration | 写入数据超时时间,默认值:无限长 | +| WithRedirectFixedPath | bool | 如果开启,当当前请求路径不能匹配上时,server 会尝试修复请求路径并重新进行匹配,如果成功匹配并且为 GET 请求则会返回状态码 301 进行重定向,其他请求方式返回 308 进行重定向。默认关闭 | +| WithBasePath | string | 设置基本路径,前缀和后缀必须为 `/`。默认为 `/` | +| WithMaxKeepBodySize | int | 设置回收时保留的请求体和响应体的最大大小。单位:字节。默认值:4 _ 1024 _ 1024 | +| WithGetOnly | bool | 如果开启则只接受 GET 请求。默认关闭 | +| WithKeepAlive | bool | 如果开启则使用 HTTP 长连接。默认开启 | +| WithAltTransport | network.NewTransporter | 设置备用 transport。默认值:netpoll.NewTransporter | +| WithH2C | bool | 设置是否开启 H2C。默认关闭 | +| WithReadBufferSize | int | 设置读缓冲区大小,同时限制 HTTP header 大小。默认值:4 \* 1024 | +| WithRegistry | registry.Registry, \*registry.Info | 设置注册中心配置,服务注册信息。默认值:registry.NoopRegistry, nil | +| WithAutoReloadRender | bool, time.Duration | 设置自动重载渲染配置。默认值:false, 0 | +| WithDisablePrintRoute | bool | 设置是否禁用 debugPrintRoute。默认不禁用 | +| WithOnAccept | func(conn net.Conn) context.Context | 设置在 netpoll 中当一个连接被接受但不能接收数据时的回调函数,在 go net 中在转换 TLS 连接之前被调用。默认值:nil | +| WithOnConnect | func(ctx context.Context, conn network.Conn) context.Context | 设置 onConnect 函数。它可以接收来自 netpoll 连接的数据。在 go net 中,它将在转换 TLS 连接后被调用。默认值:nil | +| WithDisableHeaderNamesNormalizing | bool | 设置是否禁用 Request 和 Response Header 名字的规范化 (首字母和破折号后第一个字母大写) | Server Connection 数量限制: -* 如果是使用标准网络库,无此限制 -* 如果是使用 netpoll,最大连接数为 10000 +- 如果是使用标准网络库,无此限制 +- 如果是使用 netpoll,最大连接数为 10000 (这个是 netpoll 底层使用的 [gopool](https://github.com/bytedance/gopkg/blob/b9c1c36b51a6837cef4c2223e11522e3a647460c/util/gopool/gopool.go#L46) )控制的,修改方式也很简单,调用 gopool 提供的函数即可:`gopool.SetCap(xxx)`(main.go 中调用一次即可)。 @@ -85,20 +84,20 @@ func main() { } ``` -| 配置名称 | 类型 | 说明 | -| :---- | :---- |:---| -| WithDialTimeout | time.Duration | 连接建立超时时间,默认 1s | -| WithMaxConnsPerHost | int | 设置为每个 host 建立的最大连接数,默认 512 | -| WithMaxIdleConnDuration | time.Duration | 设置空闲连接超时时间,当超时后会关闭该连接,默认 10s | -| WithMaxConnDuration | time.Duration | 设置连接存活的最大时长,超过这个时间的连接在完成当前请求后会被关闭,默认无限长 | -| WithMaxConnWaitTimeout | time.Duration | 设置等待空闲连接的最大时间,默认不等待 | -| WithKeepAlive | bool | 是否使用长连接,默认开启 | -| WithRetryConfig | ...retry.Option | 设置 client 的 retry config。Hertz 版本需 >= v0.4.0 | -| ~~WithMaxIdempotentCallAttempts~~ | int | 设置最大调用次数,调用失败则会重试。默认 1 次即不重试。v0.4.0 版本废止,该版本之前可用,建议升级 Hertz 版本 >= v0.4.0 并使用 WithRetryConfig 替代 | -| WithClientReadTimeout | time.Duration | 设置读取 response 的最长时间,默认无限长 | -| WithTLSConfig | *tls.Config | 双向 TLS 认证时,设置 client 的 TLS config | -| WithDialer | network.Dialer | 设置 client 使用的网络库,默认 netpoll | -| WithResponseBodyStream | bool | 设置是否使用流式处理,默认关闭 | -| WithDialFunc | client.DialFunc | 设置 Dial Function | -| WithWriteTimeout | time.Duration | 写入数据超时时间,默认值:无限长 | -| WithHostClientConfigHook | func(hc interface{}) error | 设置 hook 函数来重新配置 host client,传入的 func 需要将参数 hc 断言为需要的结构体,比如 http1.HostClient,再进行具体处理 | +| 配置名称 | 类型 | 说明 | +| :-------------------------------- | :------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------ | +| WithDialTimeout | time.Duration | 连接建立超时时间,默认 1s | +| WithMaxConnsPerHost | int | 设置为每个 host 建立的最大连接数,默认 512 | +| WithMaxIdleConnDuration | time.Duration | 设置空闲连接超时时间,当超时后会关闭该连接,默认 10s | +| WithMaxConnDuration | time.Duration | 设置连接存活的最大时长,超过这个时间的连接在完成当前请求后会被关闭,默认无限长 | +| WithMaxConnWaitTimeout | time.Duration | 设置等待空闲连接的最大时间,默认不等待 | +| WithKeepAlive | bool | 是否使用长连接,默认开启 | +| WithRetryConfig | ...retry.Option | 设置 client 的 retry config。Hertz 版本需 >= v0.4.0 | +| ~~WithMaxIdempotentCallAttempts~~ | int | 设置最大调用次数,调用失败则会重试。默认 1 次即不重试。v0.4.0 版本废止,该版本之前可用,建议升级 Hertz 版本 >= v0.4.0 并使用 WithRetryConfig 替代 | +| WithClientReadTimeout | time.Duration | 设置读取 response 的最长时间,默认无限长 | +| WithTLSConfig | \*tls.Config | 双向 TLS 认证时,设置 client 的 TLS config | +| WithDialer | network.Dialer | 设置 client 使用的网络库,默认 netpoll | +| WithResponseBodyStream | bool | 设置是否使用流式处理,默认关闭 | +| WithDialFunc | client.DialFunc | 设置 Dial Function | +| WithWriteTimeout | time.Duration | 写入数据超时时间,默认值:无限长 | +| WithHostClientConfigHook | func(hc interface{}) error | 设置 hook 函数来重新配置 host client,传入的 func 需要将参数 hc 断言为需要的结构体,比如 http1.HostClient,再进行具体处理 | diff --git a/content/zh/docs/hertz/reference/version.md b/content/zh/docs/hertz/reference/version.md index 45acc7a9b3..fd66ca9737 100644 --- a/content/zh/docs/hertz/reference/version.md +++ b/content/zh/docs/hertz/reference/version.md @@ -4,7 +4,6 @@ linkTitle: "版本说明" weight: 2 keywords: ["版本说明"] description: "Hertz 版本说明。" - --- Hertz 遵从 [语义化版本 2.0.0](https://semver.org/lang/zh-CN/) 发布版本。 diff --git a/content/zh/docs/hertz/tutorials/_index.md b/content/zh/docs/hertz/tutorials/_index.md index 122a78c6be..8f7b77a2da 100644 --- a/content/zh/docs/hertz/tutorials/_index.md +++ b/content/zh/docs/hertz/tutorials/_index.md @@ -2,7 +2,16 @@ title: "开发指南" linkTitle: "开发指南" weight: 3 -keywords: ["开发指南", "代码示例", "基本特性", "可观测性", "治理特性", "框架拓展", "hz 代码生成", "迁移到 Hertz"] +keywords: + [ + "开发指南", + "代码示例", + "基本特性", + "可观测性", + "治理特性", + "框架拓展", + "hz 代码生成", + "迁移到 Hertz", + ] description: "Hertz 开发指南,包括代码示例、基本特性、可观测性、治理特性、框架拓展、hz 代码生成、迁移到 Hertz。" - --- diff --git a/content/zh/docs/hertz/tutorials/basic-feature/_index.md b/content/zh/docs/hertz/tutorials/basic-feature/_index.md index 4262081117..116f91c8a7 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/_index.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/_index.md @@ -2,7 +2,27 @@ title: "基本特性" linkTitle: "基本特性" weight: 2 -keywords: ["Engine", "路由", "客户端", "网络库", "请求上下文", "中间件", "协议", "绑定与校验", "流式处理", "错误处理", "优雅退出", "正向代理和反向代理", "重试", "Hooks", "单测", "适配器", "常量", "渲染", "JSON Marshal 库"] +keywords: + [ + "Engine", + "路由", + "客户端", + "网络库", + "请求上下文", + "中间件", + "协议", + "绑定与校验", + "流式处理", + "错误处理", + "优雅退出", + "正向代理和反向代理", + "重试", + "Hooks", + "单测", + "适配器", + "常量", + "渲染", + "JSON Marshal 库", + ] description: "Hertz 基本特性。" - --- diff --git a/content/zh/docs/hertz/tutorials/basic-feature/adaptor.md b/content/zh/docs/hertz/tutorials/basic-feature/adaptor.md index 022bef2c63..d5307f41e1 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/adaptor.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/adaptor.md @@ -4,7 +4,6 @@ date: 2023-01-11 weight: 16 keywords: ["适配器", "http.Request", "http.ResponseWriter", "net/http"] description: "Hertz 提供获取 Go 标准库的 `http.Request` 和 `http.ResponseWriter` 的方式及其相关方法。" - --- Hertz 提供了获取 Go 标准库的 `http.Request` 和 `http.ResponseWriter` 的方式及其相关方法,以便于用户集成 `net/http` 进行开发。 @@ -60,24 +59,24 @@ func main() { ## http.Request -| 函数 | 函数签名 | 介绍 | -|--------------------|-----------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------| -| GetCompatRequest | `func GetCompatRequest(req *protocol.Request) (*http.Request, error)` | 通过 Hertz `protocol.Request` 构建并获取 Go 标准库 `http.Request` | +| 函数 | 函数签名 | 介绍 | +| ------------------ | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| GetCompatRequest | `func GetCompatRequest(req *protocol.Request) (*http.Request, error)` | 通过 Hertz `protocol.Request` 构建并获取 Go 标准库 `http.Request` | | CopyToHertzRequest | `func CopyToHertzRequest(req *http.Request, hreq *protocol.Request)` | 拷贝 Go 标准库 `http.Request` 的 `URI`,`Host`,`Method`,`Protocol`,`Header` 到 Hertz `protocol.Request`,对于 `Body` 属性会以共享 `Reader` 的方式进行适配 | ## http.ResponseWriter -| 函数 / 结构体 | 函数签名 | 介绍 | -|-------------------------|-----------------------------------------------------------------------------|-------------------------------------------------------------------------------------------| -| GetCompatResponseWriter | `func GetCompatResponseWriter(resp *protocol.Response) http.ResponseWriter` | 通过 Hertz `protocol.Response` 构建并获取 Go 标准库 `http.ResponseWriter` | +| 函数 / 结构体 | 函数签名 | 介绍 | +| ----------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | +| GetCompatResponseWriter | `func GetCompatResponseWriter(resp *protocol.Response) http.ResponseWriter` | 通过 Hertz `protocol.Response` 构建并获取 Go 标准库 `http.ResponseWriter` | | compatResponse | / | `compatResponse` 结构体实现了 `http.ResponseWriter` 接口并对 `Header`,`Write`,`WriteHeader` 函数进行了适配 | ## Handler Hertz 的 pprof 中间件提供了 Go 标准库 `http.Handler` 和 `http.HandlerFunc` 的适配方法,以便用户适配为 Hertz `app.HandlerFunc` 进行开发。 -| 函数 | 函数签名 | 介绍 | -|-------------------------|--------------------------------------------------------------------|-----------------------------------------------------------| +| 函数 | 函数签名 | 介绍 | +| ----------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------ | | NewHertzHTTPHandlerFunc | `func NewHertzHTTPHandlerFunc(h http.HandlerFunc) app.HandlerFunc` | 用于将 Go 标准库 `http.HandlerFunc` 转换为 Hertz `app.HandlerFunc` | | NewHertzHTTPHandler | `func NewHertzHTTPHandler(h http.Handler) app.HandlerFunc` | 用于将 Go 标准库 `http.Handler` 转换为 Hertz `app.HandlerFunc` | diff --git a/content/zh/docs/hertz/tutorials/basic-feature/binding-and-validate.md b/content/zh/docs/hertz/tutorials/basic-feature/binding-and-validate.md index daefd4c3f9..e7b2613c78 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/binding-and-validate.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/binding-and-validate.md @@ -40,21 +40,21 @@ func main() { ``` ### 全部 API -> + > hertz version >= v0.7.0 -| API | 说明 | -|:----------------------|:----------------------------------------------------------------------------------------------------------------------------------------| -| ctx.BindAndValidate | 利用下述的 go-tag 进行参数绑定,并在绑定成功后做一次参数校验 (如果有校验 tag 的话) | -| ctx.Bind | 同 `BindAndValidate` 但是不做参数校验 | -| ctx.BindQuery | 绑定所有 Query 参数,相当于给每一个 field 声明一个 `query` tag,适用于没写 tag 的场景 | -| ctx.BindHeader | 绑定所有 Header 参数,相当于给每一个 field 声明一个 `header` tag,适用于没写 tag 的场景 | -| ctx.BindPath | 绑定所有 Path 参数,相当于给每一个 field 声明一个 `path` tag,适用于没写 tag 的场景 | -| ctx.BindForm | 绑定所有 Form 参数,相当于给每一个 field 声明一个 `form` tag,需要 Content-Type 为:`application/x-www-form-urlencoded`/`multipart/form-data`, 适用于没写 tag 的场景 | -| ctx.BindJSON | 绑定 JSON Body,调用 `json.Unmarshal()` 进行反序列化,需要 Body 为 `application/json` 格式 | -| ctx.BindProtobuf | 绑定 Protobuf Body,调用 `proto.Unmarshal()` 进行反序列化,需要 Body 为 `application/x-protobuf` 格式 | -| ctx.BindByContentType | 根据 Content-Type 来自动选择绑定的方法,其中 GET 请求会调用 `BindQuery`, 带有 Body 的请求会根据 Content-Type 自动选择 | -| ctx.Validate | 进行参数校验,需要校验 tag 配合使用 (默认使用 vd tag 校验) | +| API | 说明 | +| :-------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ctx.BindAndValidate | 利用下述的 go-tag 进行参数绑定,并在绑定成功后做一次参数校验 (如果有校验 tag 的话) | +| ctx.Bind | 同 `BindAndValidate` 但是不做参数校验 | +| ctx.BindQuery | 绑定所有 Query 参数,相当于给每一个 field 声明一个 `query` tag,适用于没写 tag 的场景 | +| ctx.BindHeader | 绑定所有 Header 参数,相当于给每一个 field 声明一个 `header` tag,适用于没写 tag 的场景 | +| ctx.BindPath | 绑定所有 Path 参数,相当于给每一个 field 声明一个 `path` tag,适用于没写 tag 的场景 | +| ctx.BindForm | 绑定所有 Form 参数,相当于给每一个 field 声明一个 `form` tag,需要 Content-Type 为:`application/x-www-form-urlencoded`/`multipart/form-data`, 适用于没写 tag 的场景 | +| ctx.BindJSON | 绑定 JSON Body,调用 `json.Unmarshal()` 进行反序列化,需要 Body 为 `application/json` 格式 | +| ctx.BindProtobuf | 绑定 Protobuf Body,调用 `proto.Unmarshal()` 进行反序列化,需要 Body 为 `application/x-protobuf` 格式 | +| ctx.BindByContentType | 根据 Content-Type 来自动选择绑定的方法,其中 GET 请求会调用 `BindQuery`, 带有 Body 的请求会根据 Content-Type 自动选择 | +| ctx.Validate | 进行参数校验,需要校验 tag 配合使用 (默认使用 vd tag 校验) | ## 支持的 tag 及参数绑定优先级 @@ -64,17 +64,17 @@ func main() { 通过 IDL 生成代码时若不添加 [api 注解](/zh/docs/hertz/tutorials/toolkit/annotation/#支持的-api-注解) 则字段默认添加 `form`、`json`、`query` tag,添加 [api 注解](/zh/docs/hertz/tutorials/toolkit/annotation/#支持的-api-注解) 会为字段添加相应需求的 tag。 -| go tag | 说明 | -|:---------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| go tag | 说明 | +| :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | path | 绑定 url 上的路径参数,相当于 hertz 路由 `:param` 或 `*param` 中拿到的参数。例如:如果定义的路由为:/v:version/example,可以把 path 的参数指定为路由参数:`path:"version"`,此时,url: http://127.0.0.1:8888/v1/example,可以绑定path参数"1" | -| form | 绑定请求的 body 内容。content-type -> `multipart/form-data` 或 `application/x-www-form-urlencoded`,绑定 form 的 key-value | -| query | 绑定请求的 query 参数 | -| cookie | 绑定请求的 cookie 参数 | -| header | 绑定请求的 header 参数 | -| json | 绑定请求的 body 内容 content-type -> `application/json`,绑定 json 参数 | -| raw_body | 绑定请求的原始 body(bytes),绑定的字段名不指定,也能绑定参数。(注:raw_body 绑定优先级最低,当指定多个 tag 时,一旦其他 tag 成功绑定参数,则不会绑定 body 内容。) | -| vd | 参数校验,[校验语法](https://github.com/bytedance/go-tagexpr/tree/master/validator) | -| default | 设置默认值 | +| form | 绑定请求的 body 内容。content-type -> `multipart/form-data` 或 `application/x-www-form-urlencoded`,绑定 form 的 key-value | +| query | 绑定请求的 query 参数 | +| cookie | 绑定请求的 cookie 参数 | +| header | 绑定请求的 header 参数 | +| json | 绑定请求的 body 内容 content-type -> `application/json`,绑定 json 参数 | +| raw_body | 绑定请求的原始 body(bytes),绑定的字段名不指定,也能绑定参数。(注:raw_body 绑定优先级最低,当指定多个 tag 时,一旦其他 tag 成功绑定参数,则不会绑定 body 内容。) | +| vd | 参数校验,[校验语法](https://github.com/bytedance/go-tagexpr/tree/master/validator) | +| default | 设置默认值 | ### 参数校验 @@ -112,7 +112,7 @@ path > form > query > cookie > header > json > raw_body 通过在 tag 中添加 `required`,可以将参数标记为必传。当绑定失败时 `Bind` 和 `BindAndValidate` 将会返回错误。当多个 tag 包含 `required` 时,将会按照优先级绑定。如果**所有** tag 都没有绑定上,则会返回错误。 -``` go +```go type TagRequiredReq struct { // 当 JSON 中没有 hertz 字段时,会返回 required 错误 Hertz string `json:"hertz,required"` @@ -122,12 +122,12 @@ type TagRequiredReq struct { ``` ## 常用配置 -> + > hertz 在 v0.7.0 版本对 `参数绑定`和`校验` 进行了重构,重构后配置的行为发生变更,下面将分别介绍
> 如果还想使用之前的绑定器,目前已把其实现放到了 [hertz-contrib/binding](https://github.com/hertz-contrib/binding) 下,可通过自定义 binder 引入 -> + ### 自定义 binder -> + > hertz version >= v0.7.0 支持 需要实现 Binder 接口,并通过配置方式注入到 hertz engine @@ -201,10 +201,10 @@ func (m *mockBinder) BindProtobuf(request *protocol.Request, i interface{}) erro 目前已拓展的绑定器: -* bytedance/go-tagexpr: https://github.com/hertz-contrib/binding/tree/main/go_tagexpr (重构前使用的绑定库) +- bytedance/go-tagexpr: https://github.com/hertz-contrib/binding/tree/main/go_tagexpr (重构前使用的绑定库) ### 自定义 validator -> + > hertz version >= v0.7.0 支持 需要实现 Validator 接口,并通过配置方式注入到 hertz engine @@ -246,12 +246,13 @@ func (m *mockValidator) ValidateTag() string { 目前已拓展的校验器: -* go-playground/validator: https://github.com/hertz-contrib/binding/tree/main/go_playground +- go-playground/validator: https://github.com/hertz-contrib/binding/tree/main/go_playground ### 自定义 bind 和 validate 的 Error 在绑定参数发生错误和参数校验失败的时候,用户可以自定义 Error 的内容,使用方法如下:
**hertz version >= v0.7.0** + > 暂不支持自定义 bind error 自定义 validate error: @@ -283,7 +284,7 @@ func main() { FailField: "[validateFailField]: " + failField, Msg: "[validateErrMsg]: " + msg, } - + return &err }) h := server.New(server.WithValidateConfig(validateConfig)) @@ -385,7 +386,7 @@ func main() { return reflect.ValueOf(val), nil }) h := server.New(server.WithBindConfig(bindConfig)) - + ... h.Spin() } @@ -548,7 +549,7 @@ func init() { ``` ### 设置默认值 -> + > 重构前后使用方式都一样 参数支持 `default` tag 进行默认值的配置,使用方法如下: @@ -561,7 +562,7 @@ type UserInfoResponse struct { ``` ### 绑定文件 -> + > 重构前后使用方式一样,IDL 场景不支持文件绑定 > 文件类型需为:`multipart.FileHeader` @@ -587,10 +588,10 @@ h.POST("/upload", func(ctx context.Context, c *app.RequestContext) { 解决方法: -* 建议使用标准包 json 的 `string` tag, 例如: +- 建议使用标准包 json 的 `string` tag, 例如: ```go A int `json:"A, string"` ``` -* 配置其他支持这种行为的 json 库 +- 配置其他支持这种行为的 json 库 diff --git a/content/zh/docs/hertz/tutorials/basic-feature/client.md b/content/zh/docs/hertz/tutorials/basic-feature/client.md index 52bd95ad6d..00cc5d8c0f 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/client.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/client.md @@ -2,7 +2,8 @@ title: "客户端" date: 2023-07-25 weight: 3 -keywords: ["Client 配置", "发送请求", "请求超时", "流式处理", "中间件", "服务发现"] +keywords: + ["Client 配置", "发送请求", "请求超时", "流式处理", "中间件", "服务发现"] description: "Hertz 客户端相关功能。" --- @@ -14,7 +15,7 @@ package main import ( "context" "fmt" - + "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/client" "github.com/cloudwego/hertz/pkg/app/server" @@ -44,27 +45,27 @@ func main() { ## Client 配置 -| 配置项 | 默认值 | 描述 | -|------------------------------------|----------------|----| -| WithDialTimeout | 1s | 拨号超时时间 | -| WithMaxConnsPerHost | 512 | 每个主机可能建立的最大连接数 | -| WithMaxIdleConnDuration | 10s | 最大的空闲连接持续时间,空闲的连接在此持续时间后被关闭 | -| WithMaxConnDuration | 0s | 最大的连接持续时间,keep-alive 连接在此持续时间后被关闭 | -| WithMaxConnWaitTimeout | 0s | 等待空闲连接的最大时间 | -| WithKeepAlive | true | 是否使用 keep-alive 连接,默认使用 | -| WithClientReadTimeout | 0s | 完整读取响应(包括 body)的最大持续时间 | -| WithTLSConfig | nil | 设置用于创建 tls 连接的 tlsConfig,具体配置信息请看 [tls](/zh/docs/hertz/tutorials/basic-feature/protocol/tls/) | -| WithDialer | network.Dialer | 设置指定的拨号器 | -| WithResponseBodyStream | false | 是否在流中读取 body,默认不在流中读取 | -| WithDisableHeaderNamesNormalizing | false | 是否禁用头名称规范化,默认不禁用,如 cONTENT-lenGTH -> Content-Length | -| WithName | "" | 设置用户代理头中使用的客户端名称 | -| WithNoDefaultUserAgentHeader | false | 设置是否应该在请求中包含默认的 User-Agent 头,默认包含 User-Agent 头 | -| WithDisablePathNormalizing | false | 是否禁用路径规范化,默认规范路径,如 http://localhost:8080/hello/../ hello -> http://localhost:8080/hello | -| WithRetryConfig | nil | HTTP 客户端的重试配置,重试配置详细说明请看 [重试](/zh/docs/hertz/tutorials/basic-feature/retry/) | -| WithWriteTimeout | 0s | HTTP 客户端的写入超时时间 | -| WithConnStateObserve | nil, 5s | 设置观察和记录 HTTP 客户端的连接状态的函数以及观察执行间隔 | -| WithDialFunc | network.Dialer | 设置 HTTP 客户端拨号器函数,会覆盖自定义拨号器 | -| WithHostClientConfigHook | nil | 设置 hook 函数来重新配置 host client | +| 配置项 | 默认值 | 描述 | +| --------------------------------- | -------------- | --------------------------------------------------------------------------------------------------------------- | +| WithDialTimeout | 1s | 拨号超时时间 | +| WithMaxConnsPerHost | 512 | 每个主机可能建立的最大连接数 | +| WithMaxIdleConnDuration | 10s | 最大的空闲连接持续时间,空闲的连接在此持续时间后被关闭 | +| WithMaxConnDuration | 0s | 最大的连接持续时间,keep-alive 连接在此持续时间后被关闭 | +| WithMaxConnWaitTimeout | 0s | 等待空闲连接的最大时间 | +| WithKeepAlive | true | 是否使用 keep-alive 连接,默认使用 | +| WithClientReadTimeout | 0s | 完整读取响应(包括 body)的最大持续时间 | +| WithTLSConfig | nil | 设置用于创建 tls 连接的 tlsConfig,具体配置信息请看 [tls](/zh/docs/hertz/tutorials/basic-feature/protocol/tls/) | +| WithDialer | network.Dialer | 设置指定的拨号器 | +| WithResponseBodyStream | false | 是否在流中读取 body,默认不在流中读取 | +| WithDisableHeaderNamesNormalizing | false | 是否禁用头名称规范化,默认不禁用,如 cONTENT-lenGTH -> Content-Length | +| WithName | "" | 设置用户代理头中使用的客户端名称 | +| WithNoDefaultUserAgentHeader | false | 设置是否应该在请求中包含默认的 User-Agent 头,默认包含 User-Agent 头 | +| WithDisablePathNormalizing | false | 是否禁用路径规范化,默认规范路径,如 http://localhost:8080/hello/../ hello -> http://localhost:8080/hello | +| WithRetryConfig | nil | HTTP 客户端的重试配置,重试配置详细说明请看 [重试](/zh/docs/hertz/tutorials/basic-feature/retry/) | +| WithWriteTimeout | 0s | HTTP 客户端的写入超时时间 | +| WithConnStateObserve | nil, 5s | 设置观察和记录 HTTP 客户端的连接状态的函数以及观察执行间隔 | +| WithDialFunc | network.Dialer | 设置 HTTP 客户端拨号器函数,会覆盖自定义拨号器 | +| WithHostClientConfigHook | nil | 设置 hook 函数来重新配置 host client | 示例代码: @@ -119,14 +120,14 @@ func main() { ## Client Request 配置 -| 配置项 | 默认值 | 描述 | -| ----------------------------- | -------------- | ------------------------------------------------------- | -| WithDialTimeout | 0s | 拨号超时时间,**该配置项的优先级高于 Client 配置,即会覆盖相应的 Client 配置项** | -| WithReadTimeout | 0s | 完整读取响应(包括 body)的最大持续时间,**该配置项的优先级高于 Client 配置,即会覆盖相应的 Client 配置项** | -| WithWriteTimeout | 0s | HTTP 客户端的写入超时时间,**该配置项的优先级高于 Client 配置,即会覆盖相应的 Client 配置项** | -| WithRequestTimeout | 0s | 完整的 HTTP 请求的超时时间 | -| WithTag | make(map[string]string) | 以 key-value 形式设置 tags 字段,配合服务发现使用,详情见 [WithTag](/zh/docs/hertz/tutorials/service-governance/service_discovery/#withtag) | -| WithSD | false | 配合服务发现使用,传递 true 时,本次请求使用服务发现,详情见 [WithSD](/zh/docs/hertz/tutorials/service-governance/service_discovery/#withsd) | +| 配置项 | 默认值 | 描述 | +| ------------------ | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | +| WithDialTimeout | 0s | 拨号超时时间,**该配置项的优先级高于 Client 配置,即会覆盖相应的 Client 配置项** | +| WithReadTimeout | 0s | 完整读取响应(包括 body)的最大持续时间,**该配置项的优先级高于 Client 配置,即会覆盖相应的 Client 配置项** | +| WithWriteTimeout | 0s | HTTP 客户端的写入超时时间,**该配置项的优先级高于 Client 配置,即会覆盖相应的 Client 配置项** | +| WithRequestTimeout | 0s | 完整的 HTTP 请求的超时时间 | +| WithTag | make(map[string]string) | 以 key-value 形式设置 tags 字段,配合服务发现使用,详情见 [WithTag](/zh/docs/hertz/tutorials/service-governance/service_discovery/#withtag) | +| WithSD | false | 配合服务发现使用,传递 true 时,本次请求使用服务发现,详情见 [WithSD](/zh/docs/hertz/tutorials/service-governance/service_discovery/#withsd) | 示例代码: @@ -170,7 +171,7 @@ Do 函数执行给定的 http 请求并填充给定的 http 响应。请求必 函数签名: ```go -func (c *Client) Do(ctx context.Context, req *protocol.Request, resp *protocol.Response) error +func (c *Client) Do(ctx context.Context, req *protocol.Request, resp *protocol.Response) error ``` 示例代码: @@ -602,7 +603,7 @@ func main() { if err != nil { return } - + req, res := &protocol.Request{}, &protocol.Response{} req.SetMethod(consts.MethodGet) req.SetRequestURI("https://www.example.com") @@ -740,7 +741,7 @@ func (c *Client) Use(mws ...Middleware) 如果客户端中间件链在之前已经设置了最后一个中间件,`UseAsLast` 函数将会返回 `errorLastMiddlewareExist` 错误。因此,为确保客户端中间件链的最后一个中间件为空,可以先使用 [TakeOutLastMiddleware](#takeoutlastmiddleware) 函数清空客户端中间件链的最后一个中间件。 ->注意:`UseAsLast` 函数将中间件设置在了 `c.lastMiddleware` 中,而使用 [Use](#use) 函数设置的中间件链存放在 `c.mws` 中,两者相对独立,只是在执行客户端中间件链的最后才执行 `c.lastMiddleware`,因此 `UseAsLast` 函数在 [Use](#use) 函数之前或之后调用皆可。 +> 注意:`UseAsLast` 函数将中间件设置在了 `c.lastMiddleware` 中,而使用 [Use](#use) 函数设置的中间件链存放在 `c.mws` 中,两者相对独立,只是在执行客户端中间件链的最后才执行 `c.lastMiddleware`,因此 `UseAsLast` 函数在 [Use](#use) 函数之前或之后调用皆可。 函数签名: diff --git a/content/zh/docs/hertz/tutorials/basic-feature/constants.md b/content/zh/docs/hertz/tutorials/basic-feature/constants.md index a134e9e379..18a8b88ea1 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/constants.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/constants.md @@ -2,12 +2,18 @@ title: "常量" date: 2023-05-24 weight: 17 -keywords: ["常量", "HTTP 请求方法", "HTTP 常用 MIME 类型", "HTTP 状态码", "HTTP 头信息", "HTTP 协议版本"] +keywords: + [ + "常量", + "HTTP 请求方法", + "HTTP 常用 MIME 类型", + "HTTP 状态码", + "HTTP 头信息", + "HTTP 协议版本", + ] description: "Hertz 中定义的供用户使用的常量。" - --- - 在 Hertz 中定义了一系列的常量以供用户使用,它们都位于 [github.com/cloudwego/hertz/pkg/protocol/consts](https://github.com/cloudwego/hertz/tree/develop/pkg/protocol/consts) 。 ### HTTP 请求方法 @@ -30,7 +36,7 @@ const ( ### HTTP 常用 MIME 类型 ```go -const ( +const ( // MIME text MIMETextPlain = "text/plain" MIMETextPlainUTF8 = "text/plain; charset=utf-8" diff --git a/content/zh/docs/hertz/tutorials/basic-feature/context/request.md b/content/zh/docs/hertz/tutorials/basic-feature/context/request.md index ddf7be2fc1..da4692ebcd 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/context/request.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/context/request.md @@ -2,24 +2,36 @@ title: "请求" date: 2023-04-14 weight: 1 -keywords: ["RequestContext", "URI", "Header", "Body", "文件操作", "元数据存储", "Handler", "请求", "参数绑定与校验", "ClientIP", "并发安全"] +keywords: + [ + "RequestContext", + "URI", + "Header", + "Body", + "文件操作", + "元数据存储", + "Handler", + "请求", + "参数绑定与校验", + "ClientIP", + "并发安全", + ] description: "RequestContext 中与请求相关的功能。" --- - ## URI ```go -func (ctx *RequestContext) Host() []byte -func (ctx *RequestContext) FullPath() string +func (ctx *RequestContext) Host() []byte +func (ctx *RequestContext) FullPath() string func (ctx *RequestContext) SetFullPath(p string) -func (ctx *RequestContext) Path() []byte +func (ctx *RequestContext) Path() []byte func (ctx *RequestContext) Param(key string) string func (ctx *RequestContext) Query(key string) string func (ctx *RequestContext) DefaultQuery(key, defaultValue string) string -func (ctx *RequestContext) GetQuery(key string) (string, bool) +func (ctx *RequestContext) GetQuery(key string) (string, bool) func (ctx *RequestContext) QueryArgs() *protocol.Args -func (ctx *RequestContext) URI() *protocol.URI +func (ctx *RequestContext) URI() *protocol.URI ``` ### Host @@ -29,7 +41,7 @@ func (ctx *RequestContext) URI() *protocol.URI 函数签名: ```go -func (ctx *RequestContext) Host() []byte +func (ctx *RequestContext) Host() []byte ``` 示例: @@ -48,7 +60,7 @@ h.GET("/", func(c context.Context, ctx *app.RequestContext) { 函数签名: ```go -func (ctx *RequestContext) FullPath() string +func (ctx *RequestContext) FullPath() string ``` 示例: @@ -102,7 +114,7 @@ h.GET("/user/:name", func(c context.Context, ctx *app.RequestContext) { 函数签名: ```go -func (ctx *RequestContext) Path() []byte +func (ctx *RequestContext) Path() []byte ``` 示例: @@ -121,7 +133,7 @@ h.GET("/user/:name", func(c context.Context, ctx *app.RequestContext) { 函数签名: ```go -func (ctx *RequestContext) Param(key string) string +func (ctx *RequestContext) Param(key string) string ``` 示例: @@ -210,25 +222,25 @@ func (ctx *RequestContext) QueryArgs() *protocol.Args Args 对象提供了以下方法获取/设置 Query String 参数。 -|函数签名 | 说明 | -|:--|:--| -|`func (a *Args) Set(key, value string)` |设置 Args 对象 key 的值 | -|`func (a *Args) Reset()` |重置 Args 对象 | -|`func (a *Args) CopyTo(dst *Args)` |将 Args 对象拷贝到 dst | -|`func (a *Args) Del(key string)` |删除 Args 对象 key 的键值对 | -|`func (a *Args) DelBytes(key []byte)`|删除 Args 对象字节数组类型 key 的键值对 | -|`func (a *Args) Has(key string) bool` |获取 Args 对象是否存在 key 的键值对 | -|`func (a *Args) String() string` | 将 Args 对象转换为字符串类型的 Query String | -|`func (a *Args) QueryString() []byte` |将 Args 对象转换为字节数组类型的 Query String | -|`func (a *Args) ParseBytes(b []byte)` |解析字节数组并将键值对存入 Args 对象 | -|`func (a *Args) Peek(key string) []byte` |获取 Args 对象 key 的值 | -|`func (a *Args) PeekExists(key string) (string, bool)` |获取 Args 对象 key 的值以及是否存在 | -|`func (a *Args) PeekAll(key string) [][]byte` | 获取 Args 对象 key 的所有值 | -|`func (a *Args) Len() int`| 获取 Args 对象键值对数量 | -|`func (a *Args) AppendBytes(dst []byte) []byte` |将 Args 对象 Query String 附加到 dst 中并返回 | -|`func (a *Args) VisitAll(f func(key, value []byte))` |遍历 Args 对象所有的键值对 | -|`func (a *Args) WriteTo(w io.Writer) (int64, error)`| 将 Args 对象 Query String 写入 io.Writer 中 | -|`func (a *Args) Add(key, value string)` |添加 Args 对象键为 key 的值 | +| 函数签名 | 说明 | +| :----------------------------------------------------- | :-------------------------------------------- | +| `func (a *Args) Set(key, value string)` | 设置 Args 对象 key 的值 | +| `func (a *Args) Reset()` | 重置 Args 对象 | +| `func (a *Args) CopyTo(dst *Args)` | 将 Args 对象拷贝到 dst | +| `func (a *Args) Del(key string)` | 删除 Args 对象 key 的键值对 | +| `func (a *Args) DelBytes(key []byte)` | 删除 Args 对象字节数组类型 key 的键值对 | +| `func (a *Args) Has(key string) bool` | 获取 Args 对象是否存在 key 的键值对 | +| `func (a *Args) String() string` | 将 Args 对象转换为字符串类型的 Query String | +| `func (a *Args) QueryString() []byte` | 将 Args 对象转换为字节数组类型的 Query String | +| `func (a *Args) ParseBytes(b []byte)` | 解析字节数组并将键值对存入 Args 对象 | +| `func (a *Args) Peek(key string) []byte` | 获取 Args 对象 key 的值 | +| `func (a *Args) PeekExists(key string) (string, bool)` | 获取 Args 对象 key 的值以及是否存在 | +| `func (a *Args) PeekAll(key string) [][]byte` | 获取 Args 对象 key 的所有值 | +| `func (a *Args) Len() int` | 获取 Args 对象键值对数量 | +| `func (a *Args) AppendBytes(dst []byte) []byte` | 将 Args 对象 Query String 附加到 dst 中并返回 | +| `func (a *Args) VisitAll(f func(key, value []byte))` | 遍历 Args 对象所有的键值对 | +| `func (a *Args) WriteTo(w io.Writer) (int64, error)` | 将 Args 对象 Query String 写入 io.Writer 中 | +| `func (a *Args) Add(key, value string)` | 添加 Args 对象键为 key 的值 | 示例: @@ -261,7 +273,7 @@ h.GET("/user", func(c context.Context, ctx *app.RequestContext) { // n == 31 err == nil s := req.BodyBuffer().String() // s == "name=bar&age=&pets=dog&pets=cat" - + // change args var newArgs protocol.Args args.CopyTo(&newArgs) @@ -295,48 +307,48 @@ h.GET("/user", func(c context.Context, ctx *app.RequestContext) { 函数签名: ```go -func (ctx *RequestContext) URI() *protocol.URI +func (ctx *RequestContext) URI() *protocol.URI ``` ### URI 对象 URI 对象提供了以下方法获取/设置 URI。 -|函数签名 | 说明 | -|:--|:--| -| `func (u *URI) CopyTo(dst *URI)`| 拷贝 URI 对象的副本到 dst| -| `func (u *URI) QueryArgs() *Args`| 获取 [Args 对象](#args-对象)| -| `func (u *URI) Hash() []byte`| 获取 Hash 值,比如 的 Hash 是 **qwe** | -| `func (u *URI) SetHash(hash string)`|设置 Hash | -| `func (u *URI) SetHashBytes(hash []byte)`|设置 `[]byte` 类型 Hash | -| `func (u *URI) Username() []byte`|获取 Username| -| `func (u *URI) SetUsername(username string)`|设置 Username| -| `func (u *URI) SetUsernameBytes(username []byte)`|设置 `[]byte` 类型 Username| -| `func (u *URI) Password() []byte`|获取 Password| -| `func (u *URI) SetPassword(password string)`|设置 Password| -| `func (u *URI) SetPasswordBytes(password []byte)`|设置 `[]byte` 类型 Password| -| `func (u *URI) QueryString() []byte`|获取 `Query String`,比如 的 `Query String` 是 **baz=123**| -| `func (u *URI) SetQueryString(queryString string)`|设置 `Query String`,注意,在该方法之后使用 `RequestHeader.SetRequestURI` 可能会覆盖掉原来想设置的值 | -| `func (u *URI) SetQueryStringBytes(queryString []byte)`|设置 `[]byte` 类型的 `Query String`,注意,在该方法之后使用 `RequestHeader.SetRequestURI` 可能会覆盖掉原来想设置的值 | -| `func (u *URI) Path() []byte`| 获取 Path,比如 的 Path 是 **/user/he rtz** -| `func (u *URI) PathOriginal() []byte`|获取未转义的 Path,比如 的 Path 是 **/user/he%20rtz**| -| `func (u *URI) SetPath(path string)`|设置 Path| -| `func (u *URI) SetPathBytes(path []byte)`|设置 `[]byte` 类型 Path| -| `func (u *URI) String() string`|获取完整 URI 比如 的完整 URI 是 | -| `func (u *URI) FullURI() []byte`|获取 `[]byte` 类型的完整 URI | -| `func (u *URI) Scheme() []byte`|获取协议,如 http| -| `func (u *URI) SetScheme(scheme string)`|设置协议 | -| `func (u *URI) SetSchemeBytes(scheme []byte)`|设置 `[]byte` 类型的协议 | -| `func (u *URI) Host() []byte`|获取 Host,比如 的 Host 是 **example.com**| -| `func (u *URI) SetHost(host string)`|设置 Host| -| `func (u *URI) SetHostBytes(host []byte)`|设置 `[]byte` 类型 Host| -| `func (u *URI) LastPathSegment() []byte`|获取 Path 的最后一部分,比如 Path **/foo/bar/baz.html** 的最后一部分是 **baz.html**| -| `func (u *URI) Update(newURI string)`|更新 URI| -| `func (u *URI) UpdateBytes(newURI []byte)`|更新 `[]byte` 类型的 URI| -| `func (u *URI) Parse(host, uri []byte)`|初始化 URI| -| `func (u *URI) AppendBytes(dst []byte) []byte`|将完整的 URI 赋值到 dst 中并返回 dst| -| `func (u *URI) RequestURI() []byte`|获取 RequestURI,比如 的 RequestURI 是 **/user?baz=123**| -| `func (u *URI) Reset()`|重置 URI| +| 函数签名 | 说明 | +| :------------------------------------------------------ | :------------------------------------------------------------------------------------------------------------------- | +| `func (u *URI) CopyTo(dst *URI)` | 拷贝 URI 对象的副本到 dst | +| `func (u *URI) QueryArgs() *Args` | 获取 [Args 对象](#args-对象) | +| `func (u *URI) Hash() []byte` | 获取 Hash 值,比如 的 Hash 是 **qwe** | +| `func (u *URI) SetHash(hash string)` | 设置 Hash | +| `func (u *URI) SetHashBytes(hash []byte)` | 设置 `[]byte` 类型 Hash | +| `func (u *URI) Username() []byte` | 获取 Username | +| `func (u *URI) SetUsername(username string)` | 设置 Username | +| `func (u *URI) SetUsernameBytes(username []byte)` | 设置 `[]byte` 类型 Username | +| `func (u *URI) Password() []byte` | 获取 Password | +| `func (u *URI) SetPassword(password string)` | 设置 Password | +| `func (u *URI) SetPasswordBytes(password []byte)` | 设置 `[]byte` 类型 Password | +| `func (u *URI) QueryString() []byte` | 获取 `Query String`,比如 的 `Query String` 是 **baz=123** | +| `func (u *URI) SetQueryString(queryString string)` | 设置 `Query String`,注意,在该方法之后使用 `RequestHeader.SetRequestURI` 可能会覆盖掉原来想设置的值 | +| `func (u *URI) SetQueryStringBytes(queryString []byte)` | 设置 `[]byte` 类型的 `Query String`,注意,在该方法之后使用 `RequestHeader.SetRequestURI` 可能会覆盖掉原来想设置的值 | +| `func (u *URI) Path() []byte` | 获取 Path,比如 的 Path 是 **/user/he rtz** | +| `func (u *URI) PathOriginal() []byte` | 获取未转义的 Path,比如 的 Path 是 **/user/he%20rtz** | +| `func (u *URI) SetPath(path string)` | 设置 Path | +| `func (u *URI) SetPathBytes(path []byte)` | 设置 `[]byte` 类型 Path | +| `func (u *URI) String() string` | 获取完整 URI 比如 的完整 URI 是 | +| `func (u *URI) FullURI() []byte` | 获取 `[]byte` 类型的完整 URI | +| `func (u *URI) Scheme() []byte` | 获取协议,如 http | +| `func (u *URI) SetScheme(scheme string)` | 设置协议 | +| `func (u *URI) SetSchemeBytes(scheme []byte)` | 设置 `[]byte` 类型的协议 | +| `func (u *URI) Host() []byte` | 获取 Host,比如 的 Host 是 **example.com** | +| `func (u *URI) SetHost(host string)` | 设置 Host | +| `func (u *URI) SetHostBytes(host []byte)` | 设置 `[]byte` 类型 Host | +| `func (u *URI) LastPathSegment() []byte` | 获取 Path 的最后一部分,比如 Path **/foo/bar/baz.html** 的最后一部分是 **baz.html** | +| `func (u *URI) Update(newURI string)` | 更新 URI | +| `func (u *URI) UpdateBytes(newURI []byte)` | 更新 `[]byte` 类型的 URI | +| `func (u *URI) Parse(host, uri []byte)` | 初始化 URI | +| `func (u *URI) AppendBytes(dst []byte) []byte` | 将完整的 URI 赋值到 dst 中并返回 dst | +| `func (u *URI) RequestURI() []byte` | 获取 RequestURI,比如 的 RequestURI 是 **/user?baz=123** | +| `func (u *URI) Reset()` | 重置 URI | ## Header @@ -349,12 +361,12 @@ func (h *RequestHeader) String() string func (h *RequestHeader) VisitAll(f func(key, value []byte)) // RequestContext -func (ctx *RequestContext) IsGet() bool +func (ctx *RequestContext) IsGet() bool func (ctx *RequestContext) IsHead() bool func (ctx *RequestContext) IsPost() bool func (ctx *RequestContext) Method() []byte func (ctx *RequestContext) ContentType() []byte -func (ctx *RequestContext) IfModifiedSince(lastModified time.Time) bool +func (ctx *RequestContext) IfModifiedSince(lastModified time.Time) bool func (ctx *RequestContext) Cookie(key string) []byte func (ctx *RequestContext) UserAgent() []byte func (ctx *RequestContext) GetHeader(key string) []byte @@ -379,12 +391,12 @@ hertz.GET("/example", func(c context.Context, ctx *app.RequestContext) { ctx.Request.Header.Add("hertz1", "value1") ctx.Request.Header.Add("hertz1", "value2") ctx.Request.Header.SetContentTypeBytes([]byte("application/x-www-form-urlencoded")) - contentType1 := ctx.Request.Header.ContentType() + contentType1 := ctx.Request.Header.ContentType() // contentType1 == []byte("application/x-www-form-urlencoded") ctx.Request.Header.Add("Content-Type", "application/json; charset=utf-8") - hertz1 := ctx.Request.Header.GetAll("hertz1") + hertz1 := ctx.Request.Header.GetAll("hertz1") // hertz1 == []string{"value1", "value2"} - contentType2 := ctx.Request.Header.ContentType() + contentType2 := ctx.Request.Header.ContentType() // contentType2 == []byte("application/json; charset=utf-8") }) ``` @@ -408,12 +420,12 @@ hertz.GET("/example", func(c context.Context, ctx *app.RequestContext) { ctx.Request.Header.Set("hertz1", "value1") ctx.Request.Header.Set("hertz1", "value2") ctx.Request.Header.SetContentTypeBytes([]byte("application/x-www-form-urlencoded")) - contentType1 := ctx.Request.Header.ContentType() + contentType1 := ctx.Request.Header.ContentType() // contentType1 == []byte("application/x-www-form-urlencoded") ctx.Request.Header.Set("Content-Type", "application/json; charset=utf-8") - hertz1 := ctx.Request.Header.GetAll("hertz1") + hertz1 := ctx.Request.Header.GetAll("hertz1") // hertz1 == []string{"value2"} - contentType2 := ctx.Request.Header.ContentType() + contentType2 := ctx.Request.Header.ContentType() // contentType2 == []byte("application/json; charset=utf-8") }) ``` @@ -630,99 +642,99 @@ h.Post("/user", func(c context.Context, ctx *app.RequestContext) { 使用 `RequestContext.Request.Header` 获取 RequestHeader 对象,该对象提供了以下方法获取/设置请求头部。 -|函数签名 | 说明 | -|:--|:--| -| `func (h *RequestHeader) Method() []byte`|获取 Method | -| `func (h *RequestHeader) SetMethod(method string)`|设置 Method| -| `func (h *RequestHeader) SetMethodBytes(method []byte)`|设置 `[]byte` 类型的 Method| -| `func (h *RequestHeader) IsGet() bool`|判断 Method 是否是 GET| -| `func (h *RequestHeader) IsHead() bool`|判断 Method 是否是 HEAD| -| `func (h *RequestHeader) IsPost() bool`|判断 Method 是否是 POST| -| `func (h *RequestHeader) IsPut() bool`|判断 Method 是否是 PUT| -| `func (h *RequestHeader) IsDelete() bool`|判断 Method 是否是 DELETE| -| `func (h *RequestHeader) IsConnect() bool`|判断 Method 是否是 CONNECT| -| `func (h *RequestHeader) IsOptions() bool`|判断 Method 是否是 OPTIONS| -| `func (h *RequestHeader) IsTrace() bool`|判断 Method 是否是 TRACE| -| `func (h *RequestHeader) IgnoreBody() bool`|判断是否忽略 Body (Method GET/HEAD 忽略 Body)| -| `func (h *RequestHeader) RequestURI() []byte`| 获取 RequestURI| -| `func (h *RequestHeader) SetRequestURI(requestURI string)`|设置 RequestURI| -| `func (h *RequestHeader) SetRequestURIBytes(requestURI []byte)`|设置 `[]byte` 类型的 RequestURI| -| `func (h *RequestHeader) SetProtocol(p string)`|设置协议类型,比如 HTTP/1.0| -| `func (h *RequestHeader) GetProtocol() string`|获取协议类型,比如 HTTP/1.1| -| `func (h *RequestHeader) IsHTTP11() bool`|判断是否是 HTTP/1.1| -| `func (h *RequestHeader) SetNoHTTP11(b bool)`|设置是否不是 HTTP/1.1| -| `func (h *RequestHeader) Host() []byte`| 获取 Host| -| `func (h *RequestHeader) SetHost(host string)`|设置 Host| -| `func (h *RequestHeader) SetHostBytes(host []byte)`|设置 `[]byte` 类型的 Host| -| `func (h *RequestHeader) ContentLength() int`|获取 Content-Length| -| `func (h *RequestHeader) ContentLengthBytes() []byte`|获取 `[]byte` 类型的 Content-Length| -| `func (h *RequestHeader) SetContentLength(contentLength int)`|设置 Content-Length| -| `func (h *RequestHeader) SetContentLengthBytes(contentLength []byte)`|设置 `[]byte` 类型的 Content-Length| -| `func (h *RequestHeader) InitContentLengthWithValue(contentLength int)`|初始化 Content-Length| -| `func (h *RequestHeader) ContentType() []byte`|获取 Content-Type| -| `func (h *RequestHeader) SetContentTypeBytes(contentType []byte)`|设置 Content-Type| -| `func (h *RequestHeader) SetNoDefaultContentType(b bool)`|控制未指定 Content-Type 时的默认发送行为,false 发送默认 Content-Type 的值,true 不发送 Content-Type| -| `func (h *RequestHeader) UserAgent() []byte`|获取 User-Agent| -| `func (h *RequestHeader) SetUserAgentBytes(userAgent []byte)`|设置 User-Agent| -| `func (h *RequestHeader) ConnectionClose() bool`|判断是否包含 Connection: close| -| `func (h *RequestHeader) SetConnectionClose(close bool)`|设置 connectionClose 标志 | -| `func (h *RequestHeader) ResetConnectionClose()`|重置 connectionClose 标志为 false 并删除 Connection Header| -| `func (h *RequestHeader) SetByteRange(startPos, endPos int)`| 设置 Range (Range: bytes=startPos-endPos)| -| `func (h *RequestHeader) SetMultipartFormBoundary(boundary string)`| 当 Content-Type=multipart/form-data 时为其设置 boundary | -| `func (h *RequestHeader) MultipartFormBoundary() []byte`|获取 boundary 的值 | -| `func (h *RequestHeader) Trailer() *Trailer`|获取 Trailer| -| `func (h *RequestHeader) Cookie(key string) []byte`|获取 Cookie 键为 key 的值 | -| `func (h *RequestHeader) SetCookie(key, value string)`|设置 Cookie 的键值 | -| `func (h *RequestHeader) DelCookie(key string)`|删除键为 key 的 Cookie| -| `func (h *RequestHeader) DelAllCookies()`|删除所有 Cookie | -| `func (h *RequestHeader) FullCookie() []byte`|获取所有 Cookie| -| `func (h *RequestHeader) Cookies() []*Cookie`|获取所有 Cookie 对象 | -| `func (h *RequestHeader) VisitAllCookie(f func(key, value []byte))`| 遍历所有 Cookie 的键值并执行 f 函数 | -| `func (h *RequestHeader) Peek(key string) []byte`|获取 `[]byte` 类型的键为 key 的值 | -| `func (h *RequestHeader) Get(key string) string`|获取键为 key 的值 | -| `func (h *RequestHeader) PeekArgBytes(key []byte) []byte`|获取键为 key 的值 | -| `func (h *RequestHeader) PeekAll(key string) [][]byte`|获取 `[]byte` 类型的键为 key 的所有值(用于获取存在相同 key 的多个值)| -| `func (h *RequestHeader) GetAll(key string) []string`|获取键为 key 的所有值 | -| `func (h *RequestHeader) PeekIfModifiedSinceBytes() []byte`|获取 If-Modified-Since| -| `func (h *RequestHeader) PeekContentEncoding() []byte`|获取 Content-Encoding| -| `func (h *RequestHeader) PeekRange() []byte`|获取 Range| -| `func (h *RequestHeader) HasAcceptEncodingBytes(acceptEncoding []byte) bool`|判断是否存在 Accept-Encoding 以及 Accept-Encoding 是否包含 acceptEncoding| -| `func (h *RequestHeader) RawHeaders() []byte`|获取原始 Header | -| `func (h *RequestHeader) SetRawHeaders(r []byte)` | 设置原始 Header | -| `func (h *RequestHeader) Add(key, value string)`| 添加或设置键为 key 的 Header,用于为同一个 Key 设置多个 Header,但 key 会覆盖以下 Header: Content-Type, Content-Length, Connection, Cookie, Transfer-Encoding, Host, User-Agent| -| `func (h *RequestHeader) InitBufValue(size int)`|初始化缓冲区大小 | -| `func (h *RequestHeader) GetBufValue() []byte`|获取缓冲区的值 | -| `func (h *RequestHeader) SetCanonical(key, value []byte)`|设置 Header 键值,假设该键是规范形式 | -| `func (h *RequestHeader) Set(key, value string)`|设置 Header 键值,用于为同一个 Key 设置单个 Header | -| `func (h *RequestHeader) SetBytesKV(key, value []byte)`|设置 `[]byte` 类型的 Header 键值,用于为同一个 Key 设置单个 Header | -| `func (h *RequestHeader) DelBytes(key []byte)`|删除 Header 中键为 key 的键值对 | -| `func (h *RequestHeader) AddArgBytes(key, value []byte, noValue bool)`|添加 Header 键值(与 `Add` 不同,key 一定不会被规范化且 key 为 Content-Type, Content-Length, Connection, Cookie, Transfer-Encoding, Host, User-Agent 时不会做特殊处理)| -| `func (h *RequestHeader) SetArgBytes(key, value []byte, noValue bool)`|设置 Header 键值(与 `Set` 不同,key 一定不会被规范化且 key 为 Content-Type, Content-Length, Connection, Cookie, Transfer-Encoding, Host, User-Agent 时不会做特殊处理)| -| `func (h *RequestHeader) AppendBytes(dst []byte) []byte`|将完整的 Header 附加到 dst 中并返回 | -| `func (h *RequestHeader) Header() []byte`|获取 `[]byte` 类型的完整的 Header | -| `func (h *RequestHeader) String() string`|获取完整的 Header | -| `func (h *RequestHeader) CopyTo(dst *RequestHeader)`|获取 RequestHeader 的副本 | -| `func (h *RequestHeader) VisitAll(f func(key, value []byte))`|遍历所有 Header 的键值并执行 f 函数 | -| `func (h *RequestHeader) VisitAllCustomHeader(f func(key, value []byte))`|遍历所有 Header 的键值并执行 f 函数,以下 key 除外:Content-Type, Content-Length, Cookie, Host, User-Agent)| -| `func (h *RequestHeader) Len() int`|返回 Header 的数量 | -| `func (h *RequestHeader) DisableNormalizing()`|禁用 Header 名字的规范化 (首字母和破折号后第一个字母大写)| -| `func (h *RequestHeader) IsDisableNormalizing() bool`|是否禁用 Header 名字的规范化,默认不禁用 | -| `func (h *RequestHeader) ResetSkipNormalize()`|重置 Headers,除了 disableNormalizing 状态 | -| `func (h *RequestHeader) Reset()`|重置 Headers | +| 函数签名 | 说明 | +| :--------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `func (h *RequestHeader) Method() []byte` | 获取 Method | +| `func (h *RequestHeader) SetMethod(method string)` | 设置 Method | +| `func (h *RequestHeader) SetMethodBytes(method []byte)` | 设置 `[]byte` 类型的 Method | +| `func (h *RequestHeader) IsGet() bool` | 判断 Method 是否是 GET | +| `func (h *RequestHeader) IsHead() bool` | 判断 Method 是否是 HEAD | +| `func (h *RequestHeader) IsPost() bool` | 判断 Method 是否是 POST | +| `func (h *RequestHeader) IsPut() bool` | 判断 Method 是否是 PUT | +| `func (h *RequestHeader) IsDelete() bool` | 判断 Method 是否是 DELETE | +| `func (h *RequestHeader) IsConnect() bool` | 判断 Method 是否是 CONNECT | +| `func (h *RequestHeader) IsOptions() bool` | 判断 Method 是否是 OPTIONS | +| `func (h *RequestHeader) IsTrace() bool` | 判断 Method 是否是 TRACE | +| `func (h *RequestHeader) IgnoreBody() bool` | 判断是否忽略 Body (Method GET/HEAD 忽略 Body) | +| `func (h *RequestHeader) RequestURI() []byte` | 获取 RequestURI | +| `func (h *RequestHeader) SetRequestURI(requestURI string)` | 设置 RequestURI | +| `func (h *RequestHeader) SetRequestURIBytes(requestURI []byte)` | 设置 `[]byte` 类型的 RequestURI | +| `func (h *RequestHeader) SetProtocol(p string)` | 设置协议类型,比如 HTTP/1.0 | +| `func (h *RequestHeader) GetProtocol() string` | 获取协议类型,比如 HTTP/1.1 | +| `func (h *RequestHeader) IsHTTP11() bool` | 判断是否是 HTTP/1.1 | +| `func (h *RequestHeader) SetNoHTTP11(b bool)` | 设置是否不是 HTTP/1.1 | +| `func (h *RequestHeader) Host() []byte` | 获取 Host | +| `func (h *RequestHeader) SetHost(host string)` | 设置 Host | +| `func (h *RequestHeader) SetHostBytes(host []byte)` | 设置 `[]byte` 类型的 Host | +| `func (h *RequestHeader) ContentLength() int` | 获取 Content-Length | +| `func (h *RequestHeader) ContentLengthBytes() []byte` | 获取 `[]byte` 类型的 Content-Length | +| `func (h *RequestHeader) SetContentLength(contentLength int)` | 设置 Content-Length | +| `func (h *RequestHeader) SetContentLengthBytes(contentLength []byte)` | 设置 `[]byte` 类型的 Content-Length | +| `func (h *RequestHeader) InitContentLengthWithValue(contentLength int)` | 初始化 Content-Length | +| `func (h *RequestHeader) ContentType() []byte` | 获取 Content-Type | +| `func (h *RequestHeader) SetContentTypeBytes(contentType []byte)` | 设置 Content-Type | +| `func (h *RequestHeader) SetNoDefaultContentType(b bool)` | 控制未指定 Content-Type 时的默认发送行为,false 发送默认 Content-Type 的值,true 不发送 Content-Type | +| `func (h *RequestHeader) UserAgent() []byte` | 获取 User-Agent | +| `func (h *RequestHeader) SetUserAgentBytes(userAgent []byte)` | 设置 User-Agent | +| `func (h *RequestHeader) ConnectionClose() bool` | 判断是否包含 Connection: close | +| `func (h *RequestHeader) SetConnectionClose(close bool)` | 设置 connectionClose 标志 | +| `func (h *RequestHeader) ResetConnectionClose()` | 重置 connectionClose 标志为 false 并删除 Connection Header | +| `func (h *RequestHeader) SetByteRange(startPos, endPos int)` | 设置 Range (Range: bytes=startPos-endPos) | +| `func (h *RequestHeader) SetMultipartFormBoundary(boundary string)` | 当 Content-Type=multipart/form-data 时为其设置 boundary | +| `func (h *RequestHeader) MultipartFormBoundary() []byte` | 获取 boundary 的值 | +| `func (h *RequestHeader) Trailer() *Trailer` | 获取 Trailer | +| `func (h *RequestHeader) Cookie(key string) []byte` | 获取 Cookie 键为 key 的值 | +| `func (h *RequestHeader) SetCookie(key, value string)` | 设置 Cookie 的键值 | +| `func (h *RequestHeader) DelCookie(key string)` | 删除键为 key 的 Cookie | +| `func (h *RequestHeader) DelAllCookies()` | 删除所有 Cookie | +| `func (h *RequestHeader) FullCookie() []byte` | 获取所有 Cookie | +| `func (h *RequestHeader) Cookies() []*Cookie` | 获取所有 Cookie 对象 | +| `func (h *RequestHeader) VisitAllCookie(f func(key, value []byte))` | 遍历所有 Cookie 的键值并执行 f 函数 | +| `func (h *RequestHeader) Peek(key string) []byte` | 获取 `[]byte` 类型的键为 key 的值 | +| `func (h *RequestHeader) Get(key string) string` | 获取键为 key 的值 | +| `func (h *RequestHeader) PeekArgBytes(key []byte) []byte` | 获取键为 key 的值 | +| `func (h *RequestHeader) PeekAll(key string) [][]byte` | 获取 `[]byte` 类型的键为 key 的所有值(用于获取存在相同 key 的多个值) | +| `func (h *RequestHeader) GetAll(key string) []string` | 获取键为 key 的所有值 | +| `func (h *RequestHeader) PeekIfModifiedSinceBytes() []byte` | 获取 If-Modified-Since | +| `func (h *RequestHeader) PeekContentEncoding() []byte` | 获取 Content-Encoding | +| `func (h *RequestHeader) PeekRange() []byte` | 获取 Range | +| `func (h *RequestHeader) HasAcceptEncodingBytes(acceptEncoding []byte) bool` | 判断是否存在 Accept-Encoding 以及 Accept-Encoding 是否包含 acceptEncoding | +| `func (h *RequestHeader) RawHeaders() []byte` | 获取原始 Header | +| `func (h *RequestHeader) SetRawHeaders(r []byte)` | 设置原始 Header | +| `func (h *RequestHeader) Add(key, value string)` | 添加或设置键为 key 的 Header,用于为同一个 Key 设置多个 Header,但 key 会覆盖以下 Header: Content-Type, Content-Length, Connection, Cookie, Transfer-Encoding, Host, User-Agent | +| `func (h *RequestHeader) InitBufValue(size int)` | 初始化缓冲区大小 | +| `func (h *RequestHeader) GetBufValue() []byte` | 获取缓冲区的值 | +| `func (h *RequestHeader) SetCanonical(key, value []byte)` | 设置 Header 键值,假设该键是规范形式 | +| `func (h *RequestHeader) Set(key, value string)` | 设置 Header 键值,用于为同一个 Key 设置单个 Header | +| `func (h *RequestHeader) SetBytesKV(key, value []byte)` | 设置 `[]byte` 类型的 Header 键值,用于为同一个 Key 设置单个 Header | +| `func (h *RequestHeader) DelBytes(key []byte)` | 删除 Header 中键为 key 的键值对 | +| `func (h *RequestHeader) AddArgBytes(key, value []byte, noValue bool)` | 添加 Header 键值(与 `Add` 不同,key 一定不会被规范化且 key 为 Content-Type, Content-Length, Connection, Cookie, Transfer-Encoding, Host, User-Agent 时不会做特殊处理) | +| `func (h *RequestHeader) SetArgBytes(key, value []byte, noValue bool)` | 设置 Header 键值(与 `Set` 不同,key 一定不会被规范化且 key 为 Content-Type, Content-Length, Connection, Cookie, Transfer-Encoding, Host, User-Agent 时不会做特殊处理) | +| `func (h *RequestHeader) AppendBytes(dst []byte) []byte` | 将完整的 Header 附加到 dst 中并返回 | +| `func (h *RequestHeader) Header() []byte` | 获取 `[]byte` 类型的完整的 Header | +| `func (h *RequestHeader) String() string` | 获取完整的 Header | +| `func (h *RequestHeader) CopyTo(dst *RequestHeader)` | 获取 RequestHeader 的副本 | +| `func (h *RequestHeader) VisitAll(f func(key, value []byte))` | 遍历所有 Header 的键值并执行 f 函数 | +| `func (h *RequestHeader) VisitAllCustomHeader(f func(key, value []byte))` | 遍历所有 Header 的键值并执行 f 函数,以下 key 除外:Content-Type, Content-Length, Cookie, Host, User-Agent) | +| `func (h *RequestHeader) Len() int` | 返回 Header 的数量 | +| `func (h *RequestHeader) DisableNormalizing()` | 禁用 Header 名字的规范化 (首字母和破折号后第一个字母大写) | +| `func (h *RequestHeader) IsDisableNormalizing() bool` | 是否禁用 Header 名字的规范化,默认不禁用 | +| `func (h *RequestHeader) ResetSkipNormalize()` | 重置 Headers,除了 disableNormalizing 状态 | +| `func (h *RequestHeader) Reset()` | 重置 Headers | ## Body ```go func (ctx *RequestContext) GetRawData() []byte -func (ctx *RequestContext) Body() ([]byte, error) +func (ctx *RequestContext) Body() ([]byte, error) func (ctx *RequestContext) RequestBodyStream() io.Reader func (ctx *RequestContext) MultipartForm() (*multipart.Form, error) func (ctx *RequestContext) PostForm(key string) string -func (ctx *RequestContext) DefaultPostForm(key, defaultValue string) string -func (ctx *RequestContext) GetPostForm(key string) (string, bool) +func (ctx *RequestContext) DefaultPostForm(key, defaultValue string) string +func (ctx *RequestContext) GetPostForm(key string) (string, bool) func (ctx *RequestContext) PostArgs() *protocol.Args -func (ctx *RequestContext) FormValue(key string) []byte -func (ctx *RequestContext) SetFormValueFunc(f FormValueFunc) +func (ctx *RequestContext) FormValue(key string) []byte +func (ctx *RequestContext) SetFormValueFunc(f FormValueFunc) ``` ### Body @@ -732,7 +744,7 @@ func (ctx *RequestContext) SetFormValueFunc(f FormValueFunc) 函数签名: ```go -func (ctx *RequestContext) Body() ([]byte, error) +func (ctx *RequestContext) Body() ([]byte, error) ``` 示例: @@ -785,7 +797,7 @@ func (ctx *RequestContext) MultipartForm() (*multipart.Form, error) ```go // POST http://example.com/user -// Content-Type: multipart/form-data; +// Content-Type: multipart/form-data; // Content-Disposition: form-data; name="name" // tom h.POST("/user", func(c context.Context, ctx *app.RequestContext) { @@ -810,7 +822,7 @@ func (ctx *RequestContext) PostForm(key string) string ```go // POST http://example.com/user -// Content-Type: multipart/form-data; +// Content-Type: multipart/form-data; // Content-Disposition: form-data; name="name" // tom h.POST("/user", func(c context.Context, ctx *app.RequestContext) { @@ -827,14 +839,14 @@ h.POST("/user", func(c context.Context, ctx *app.RequestContext) { 函数签名: ```go -func (ctx *RequestContext) DefaultPostForm(key, defaultValue string) string +func (ctx *RequestContext) DefaultPostForm(key, defaultValue string) string ``` 示例: ```go // POST http://example.com/user -// Content-Type: multipart/form-data; +// Content-Type: multipart/form-data; // Content-Disposition: form-data; name="name" // tom h.POST("/user", func(c context.Context, ctx *app.RequestContext) { @@ -884,7 +896,7 @@ h.POST("/user", func(c context.Context, ctx *app.RequestContext) { 函数签名: ```go -func (ctx *RequestContext) FormValue(key string) []byte +func (ctx *RequestContext) FormValue(key string) []byte ``` 示例: @@ -899,7 +911,7 @@ h.POST("/user", func(c context.Context, ctx *app.RequestContext) { }) // POST http://example.com/user -// Content-Type: multipart/form-data; +// Content-Type: multipart/form-data; // Content-Disposition: form-data; name="name" // tom h.POST("/user", func(c context.Context, ctx *app.RequestContext) { @@ -914,14 +926,14 @@ h.POST("/user", func(c context.Context, ctx *app.RequestContext) { 函数签名: ```go -func (ctx *RequestContext) SetFormValueFunc(f FormValueFunc) +func (ctx *RequestContext) SetFormValueFunc(f FormValueFunc) ``` 示例: ```go // POST http://example.com/user?name=tom -// Content-Type: multipart/form-data; +// Content-Type: multipart/form-data; // Content-Disposition: form-data; name="age" // 10 h.POST("/user", func(c context.Context, ctx *app.RequestContext) { @@ -946,8 +958,8 @@ h.POST("/user", func(c context.Context, ctx *app.RequestContext) { ```go func (ctx *RequestContext) MultipartForm() (*multipart.Form, error) -func (ctx *RequestContext) FormFile(name string) (*multipart.FileHeader, error) -func (ctx *RequestContext) SaveUploadedFile(file *multipart.FileHeader, dst string) error +func (ctx *RequestContext) FormFile(name string) (*multipart.FileHeader, error) +func (ctx *RequestContext) SaveUploadedFile(file *multipart.FileHeader, dst string) error ``` ### MultipartForm @@ -966,7 +978,7 @@ func (ctx *RequestContext) MultipartForm() (*multipart.Form, error) ```go // POST http://example.com/user -// Content-Type: multipart/form-data; +// Content-Type: multipart/form-data; // Content-Disposition: form-data; name="avatar"; filename="abc.jpg" h.POST("/user", func(c context.Context, ctx *app.RequestContext) { form, err := ctx.MultipartForm() @@ -981,14 +993,14 @@ h.POST("/user", func(c context.Context, ctx *app.RequestContext) { 函数签名: ```go -func (ctx *RequestContext) FormFile(name string) (*multipart.FileHeader, error) +func (ctx *RequestContext) FormFile(name string) (*multipart.FileHeader, error) ``` 示例: ```go // POST http://example.com/user -// Content-Type: multipart/form-data; +// Content-Type: multipart/form-data; // Content-Disposition: form-data; name="avatar"; filename="abc.jpg" h.Post("/user", func(c context.Context, ctx *app.RequestContext) { avatarFile, err := ctx.FormFile("avatar") // avatarFile.Filename == "abc.jpg", err == nil @@ -1002,14 +1014,14 @@ h.Post("/user", func(c context.Context, ctx *app.RequestContext) { 函数签名: ```go -func (ctx *RequestContext) SaveUploadedFile(file *multipart.FileHeader, dst string) error +func (ctx *RequestContext) SaveUploadedFile(file *multipart.FileHeader, dst string) error ``` 示例: ```go // POST http://example.com/user -// Content-Type: multipart/form-data; +// Content-Type: multipart/form-data; // Content-Disposition: form-data; name="avatar"; filename="abc.jpg" h.Post("/user", func(c context.Context, ctx *app.RequestContext) { avatarFile, err := ctx.FormFile("avatar") // avatarFile.Filename == "abc.jpg", err == nil @@ -1022,29 +1034,29 @@ h.Post("/user", func(c context.Context, ctx *app.RequestContext) { > 注意:RequestContext 在请求结束后会被回收,元数据会被置为 nil。如需异步使用,请使用 [Copy](#copy) 方法。 -|函数签名 | 说明 | -|:--|:--| -| `func (ctx *RequestContext) Set(key string, value interface{})`|在上下文中存储键值对 | -| `func (ctx *RequestContext) Value(key interface{}) interface{}`|获取上下文键为 key 的值 | -| `func (ctx *RequestContext) Get(key string) (value interface{}, exists bool)`|获取上下文键为 key 的值以及 key 是否存在 | -| `func (ctx *RequestContext) MustGet(key string) interface{}`|获取上下文键为 key 的值,如果不存在会发生 panic| -| `func (ctx *RequestContext) GetString(key string) (s string)`|获取上下文键为 key 的值,并转换为 `string` 类型 | -| `func (ctx *RequestContext) GetBool(key string) (b bool)`|获取上下文键为 key 的值,并转换为 `bool` 类型 | -| `func (ctx *RequestContext) GetInt(key string) (i int)`|获取上下文键为 key 的值,并转换为 `int` 类型 | -| `func (ctx *RequestContext) GetInt32(key string) (i32 int32)`|获取上下文键为 key 的值,并转换为 `int32` 类型 | -| `func (ctx *RequestContext) GetInt64(key string) (i64 int64)`|获取上下文键为 key 的值,并转换为 `int64` 类型 | -| `func (ctx *RequestContext) GetUint(key string) (ui uint)`|获取上下文键为 key 的值,并转换为 `uint` 类型 | -| `func (ctx *RequestContext) GetUint32(key string) (ui32 uint32)`|获取上下文键为 key 的值,并转换为 `uint32` 类型 | -| `func (ctx *RequestContext) GetUint64(key string) (ui64 uint64)`|获取上下文键为 key 的值,并转换为 `uint64` 类型 | -| `func (ctx *RequestContext) GetFloat32(key string) (f32 float32)`|获取上下文键为 key 的值,并转换为 `float32` 类型 | -| `func (ctx *RequestContext) GetFloat64(key string) (f64 float64)`|获取上下文键为 key 的值,并转换为 `float64` 类型 | -| `func (ctx *RequestContext) GetTime(key string) (t time.Time)`|获取上下文键为 key 的值,并转换为 `time.Time` 类型 | -| `func (ctx *RequestContext) GetDuration(key string) (d time.Duration)`|获取上下文键为 key 的值,并转换为 `time.Duration` 类型 | -| `func (ctx *RequestContext) GetStringSlice(key string) (ss []string)`|获取上下文键为 key 的值,并转换为 `[]string` 类型 | -| `func (ctx *RequestContext) GetStringMap(key string) (sm map[string]interface{})`|获取上下文键为 key 的值,并转换为 `map[string]interface{}` 类型 | -| `func (ctx *RequestContext) GetStringMapString(key string) (sms map[string]string)`|获取上下文键为 key 的值,并转换为 `map[string]string` 类型 | -| `func (ctx *RequestContext) GetStringMapStringSlice(key string) (smss map[string][]string)`|获取上下文键为 key 的值,并转换为 `map[string][]string` 类型 | -| `func (ctx *RequestContext) ForEachKey(fn func(k string, v interface{}))`|为上下文中的每个键值对调用 fn | +| 函数签名 | 说明 | +| :------------------------------------------------------------------------------------------ | :-------------------------------------------------------------- | +| `func (ctx *RequestContext) Set(key string, value interface{})` | 在上下文中存储键值对 | +| `func (ctx *RequestContext) Value(key interface{}) interface{}` | 获取上下文键为 key 的值 | +| `func (ctx *RequestContext) Get(key string) (value interface{}, exists bool)` | 获取上下文键为 key 的值以及 key 是否存在 | +| `func (ctx *RequestContext) MustGet(key string) interface{}` | 获取上下文键为 key 的值,如果不存在会发生 panic | +| `func (ctx *RequestContext) GetString(key string) (s string)` | 获取上下文键为 key 的值,并转换为 `string` 类型 | +| `func (ctx *RequestContext) GetBool(key string) (b bool)` | 获取上下文键为 key 的值,并转换为 `bool` 类型 | +| `func (ctx *RequestContext) GetInt(key string) (i int)` | 获取上下文键为 key 的值,并转换为 `int` 类型 | +| `func (ctx *RequestContext) GetInt32(key string) (i32 int32)` | 获取上下文键为 key 的值,并转换为 `int32` 类型 | +| `func (ctx *RequestContext) GetInt64(key string) (i64 int64)` | 获取上下文键为 key 的值,并转换为 `int64` 类型 | +| `func (ctx *RequestContext) GetUint(key string) (ui uint)` | 获取上下文键为 key 的值,并转换为 `uint` 类型 | +| `func (ctx *RequestContext) GetUint32(key string) (ui32 uint32)` | 获取上下文键为 key 的值,并转换为 `uint32` 类型 | +| `func (ctx *RequestContext) GetUint64(key string) (ui64 uint64)` | 获取上下文键为 key 的值,并转换为 `uint64` 类型 | +| `func (ctx *RequestContext) GetFloat32(key string) (f32 float32)` | 获取上下文键为 key 的值,并转换为 `float32` 类型 | +| `func (ctx *RequestContext) GetFloat64(key string) (f64 float64)` | 获取上下文键为 key 的值,并转换为 `float64` 类型 | +| `func (ctx *RequestContext) GetTime(key string) (t time.Time)` | 获取上下文键为 key 的值,并转换为 `time.Time` 类型 | +| `func (ctx *RequestContext) GetDuration(key string) (d time.Duration)` | 获取上下文键为 key 的值,并转换为 `time.Duration` 类型 | +| `func (ctx *RequestContext) GetStringSlice(key string) (ss []string)` | 获取上下文键为 key 的值,并转换为 `[]string` 类型 | +| `func (ctx *RequestContext) GetStringMap(key string) (sm map[string]interface{})` | 获取上下文键为 key 的值,并转换为 `map[string]interface{}` 类型 | +| `func (ctx *RequestContext) GetStringMapString(key string) (sms map[string]string)` | 获取上下文键为 key 的值,并转换为 `map[string]string` 类型 | +| `func (ctx *RequestContext) GetStringMapStringSlice(key string) (smss map[string][]string)` | 获取上下文键为 key 的值,并转换为 `map[string][]string` 类型 | +| `func (ctx *RequestContext) ForEachKey(fn func(k string, v interface{}))` | 为上下文中的每个键值对调用 fn | 示例: @@ -1123,13 +1135,13 @@ h.POST("/user", func(c context.Context, ctx *app.RequestContext) { ## Handler ```go -func (ctx *RequestContext) Next(c context.Context) -func (ctx *RequestContext) Handlers() HandlersChain -func (ctx *RequestContext) Handler() HandlerFunc -func (ctx *RequestContext) SetHandlers(hc HandlersChain) -func (ctx *RequestContext) HandlerName() string -func (ctx *RequestContext) GetIndex() int8 -func (ctx *RequestContext) Abort() +func (ctx *RequestContext) Next(c context.Context) +func (ctx *RequestContext) Handlers() HandlersChain +func (ctx *RequestContext) Handler() HandlerFunc +func (ctx *RequestContext) SetHandlers(hc HandlersChain) +func (ctx *RequestContext) HandlerName() string +func (ctx *RequestContext) GetIndex() int8 +func (ctx *RequestContext) Abort() func (ctx *RequestContext) IsAborted() bool ``` @@ -1317,16 +1329,16 @@ h.POST("/user", func(c context.Context, ctx *app.RequestContext) { (更多内容请参考 [binding-and-validate](/zh/docs/hertz/tutorials/basic-feature/binding-and-validate)) ```go -func (ctx *RequestContext) Bind(obj interface{}) error -func (ctx *RequestContext) Validate(obj interface{}) error +func (ctx *RequestContext) Bind(obj interface{}) error +func (ctx *RequestContext) Validate(obj interface{}) error func (ctx *RequestContext) BindAndValidate(obj interface{}) error ``` ## 获取 ClientIP ```go -func (ctx *RequestContext) ClientIP() string -func (ctx *RequestContext) SetClientIPFunc(f ClientIP) +func (ctx *RequestContext) ClientIP() string +func (ctx *RequestContext) SetClientIPFunc(f ClientIP) ``` ### ClientIP @@ -1338,7 +1350,7 @@ func (ctx *RequestContext) SetClientIPFunc(f ClientIP) 函数签名: ```go -func (ctx *RequestContext) ClientIP() string +func (ctx *RequestContext) ClientIP() string ``` 示例: @@ -1362,7 +1374,7 @@ h.Use(func(c context.Context, ctx *app.RequestContext) { 函数签名: ```go -func (ctx *RequestContext) SetClientIPFunc(f ClientIP) +func (ctx *RequestContext) SetClientIPFunc(f ClientIP) ``` 示例: @@ -1403,7 +1415,7 @@ func (ctx *RequestContext) Copy() *RequestContext 函数签名: ```go -func (ctx *RequestContext) Copy() *RequestContext +func (ctx *RequestContext) Copy() *RequestContext ``` 示例: diff --git a/content/zh/docs/hertz/tutorials/basic-feature/context/response.md b/content/zh/docs/hertz/tutorials/basic-feature/context/response.md index 2b7fd4b506..706c5dce1d 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/context/response.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/context/response.md @@ -2,7 +2,8 @@ title: "响应" date: 2023-04-14 weight: 2 -keywords: ["RequestContext", "渲染", "Header", "Body", "文件操作", "响应", "Flush"] +keywords: + ["RequestContext", "渲染", "Header", "Body", "文件操作", "响应", "Flush"] description: "RequestContext 中与响应相关的功能。" --- @@ -20,7 +21,7 @@ func (ctx *RequestContext) Redirect(statusCode int, uri []byte) func (ctx *RequestContext) Header(key, value string) func (ctx *RequestContext) SetCookie(name, value string, maxAge int, path, domain string, sameSite protocol.CookieSameSite, secure, httpOnly bool) func (ctx *RequestContext) AbortWithStatus(code int) -func (ctx *RequestContext) AbortWithError(code int, err error) *errors.Error +func (ctx *RequestContext) AbortWithError(code int, err error) *errors.Error ``` ### SetContentType @@ -226,7 +227,7 @@ func (ctx *RequestContext) SetCookie(name, value string, maxAge int, path, domai ```go h.GET("/user", func(c context.Context, ctx *app.RequestContext) { ctx.SetCookie("user", "hertz", 1, "/", "localhost", protocol.CookieSameSiteLaxMode, true, true) - cookie := ctx.Response.Header.Get("Set-Cookie") + cookie := ctx.Response.Header.Get("Set-Cookie") // cookie == "user=hertz; max-age=1; domain=localhost; path=/; HttpOnly; secure; SameSite=Lax" }) ``` @@ -248,7 +249,7 @@ func SetPartitionedCookie(ctx *app.RequestContext, name, value string, maxAge in } cookie := protocol.AcquireCookie() defer protocol.ReleaseCookie(cookie) - // It is recommended to use the __Host prefix when setting partitioned cookies + // It is recommended to use the __Host prefix when setting partitioned cookies // to make them bound to the hostname (and not the registrable domain). cookie.SetKey(name) cookie.SetValue(url.QueryEscape(value)) @@ -305,7 +306,7 @@ h.GET("/user", func(c context.Context, ctx *app.RequestContext) { 函数签名: ```go -func (ctx *RequestContext) AbortWithError(code int, err error) *errors.Error +func (ctx *RequestContext) AbortWithError(code int, err error) *errors.Error ``` 示例: @@ -324,66 +325,66 @@ h.GET("/user", func(c context.Context, ctx *app.RequestContext) { 使用 RequestContext.Response.Header 获取 ResponseHeader 对象,该对象提供了以下方法获取/设置响应头部。 -|函数签名 | 说明 | -|:--|:--| -|`func (h *ResponseHeader) IsHTTP11() bool` |判断是否是 `HTTP/1.1` 协议,true 表示是 `HTTP/1.1` 协议 | -|`func (h *ResponseHeader) SetHeaderLength(length int)` |设置响应头的大小 | -|`func (h *ResponseHeader) GetHeaderLength()` |获取响应头的大小 | -|`func (h *ResponseHeader) SetContentRange(startPos, endPos, contentLength int)` |在响应头中设置 `Content-Range: bytes startPos-endPos/contentLength`,如 `Content-Range: bytes 1-5/10` | -|`func (h *ResponseHeader) NoDefaultContentType() bool` |获取未指定 Content-Type 时的默认发送行为,false 表示发送默认 Content-Type 的值,true 表示不发送,默认 Content-Type 的值为 `text/plain; charset=utf-8` | -|`func (h *ResponseHeader) SetNoDefaultContentType(b bool)` |设置未指定 Content-Type 时的默认发送行为,false 表示发送默认 Content-Type 的值,true 表示不发送,默认 Content-Type 的值为 `text/plain; charset=utf-8` | -|`func (h *ResponseHeader) SetContentType(contentType string)` |设置 Content-Type | -|`func (h *ResponseHeader) ContentType() []byte` |获取 Content-Type | -|`func (h *ResponseHeader) SetContentTypeBytes(contentType []byte)` |设置 Content-Type | -|`func (h *ResponseHeader) ContentLength() int` |获取 Content-Length,可以是负值,-1 表示 `Transfer-Encoding: chunked`,-2 表示 `Transfer-Encoding: identity` | -|`func (h *ResponseHeader) SetContentLength(contentLength int)` |设置 Content-Length,可以是负值,-1 表示 `Transfer-Encoding: chunked`,-2 表示 `Transfer-Encoding: identity` | -|`func (h *ResponseHeader) SetContentLengthBytes(contentLength []byte)` |设置 `[]byte` 类型的 Content-Length,可以是负值,-1 表示 `Transfer-Encoding: chunked`,-2 表示 `Transfer-Encoding: identity` | -|`func (h *ResponseHeader) CopyTo(dst *ResponseHeader)` |返回响应头的副本,在对响应头存在竞争访问时可以使用 | -|`func (h *ResponseHeader) GetHeaders() []argsKV` |以键值对的形式返回所有响应头 | -|`func (h *ResponseHeader) VisitAll(f func(key, value []byte))` |遍历所有 Header 的键值并执行 f 函数 | -|`func (h *ResponseHeader) Get(key string) string` |获取键为 key 的值,并发安全 | -|`func (h *ResponseHeader) GetAll(key string) []string` |获取 `[]byte` 类型的键为 key 的所有值(用于获取存在相同 key 的多个值),并发安全 | -|`func (h *ResponseHeader) Peek(key string) []byte` |获取 `[]byte` 类型的键为 key 的值,并发不安全,竞争访问时使用 `Get` | -|`func (h *ResponseHeader) PeekAll(key string) [][]byte` |获取 `[]byte` 类型的键为 key 的所有值(用于获取存在相同 key 的多个值),并发不安全,竞争访问时使用 `GetAll` | -|`func (h *ResponseHeader) Set(key, value string)` |设置 Header 键值,用于为同一个 Key 设置单个 Header | -|`func (h *ResponseHeader) SetBytesV(key string, value []byte)` |设置 `[]byte` 类型的 Header 键值,用于为同一个 Key 设置单个 Header | -|`func (h *ResponseHeader) Add(key, value string)` |设置 Header 键值,用于为同一个 Key 设置多个 Header,但 key 会覆盖以下 Header: Content-Type, Content-Length, Connection, Cookie, Transfer-Encoding, Host, User-Agent | -| `func (h *ResponseHeader) AddArgBytes(key, value []byte, noValue bool)`|添加 Header 键值(与 `Add` 不同,key 一定不会被规范化且 key 为 Content-Type, Content-Length, Content-Encoding, Connection, Server, Set-Cookie, Transfer-Encoding 时不会做特殊处理)| -| `func (h *ResponseHeader) SetArgBytes(key, value []byte, noValue bool)`|设置 Header 键值(与 `Set` 不同,key 一定不会被规范化且 key 为 Content-Type, Content-Length, Content-Encoding, Connection, Server, Set-Cookie, Transfer-Encoding 时不会做特殊处理)| -|`func (h *ResponseHeader) Del(key string)` |删除 Header 中键为 key 的键值对 | -|`func (h *ResponseHeader) DelBytes(key []byte)` |删除 Header 中键为 key 的键值对 | -|`func (h *ResponseHeader) AppendBytes(dst []byte) []byte` |将完整的 Header 附加到 dst 中并返回 | -|`func (h *ResponseHeader) Header() []byte` |获取 `[]byte` 类型的完整的 Header | -|`func (h *ResponseHeader) PeekLocation() []byte` |返回 Header 中 key 为 `Location` 的值 | -|`func (h *ResponseHeader) Cookie(cookie *Cookie) bool` |填充给定 cookie.Key 的 cookie,如果 cookie.Key 不存在则返回 false | -|`func (h *RequestHeader) FullCookie() []byte` |以字节数组形式返回完整的 cookie | -|`func (h *ResponseHeader) SetCookie(cookie *Cookie)` |设置 Cookie 的键值 | -|`func (h *ResponseHeader) VisitAllCookie(f func(key, value []byte))` |遍历所有 Cookie 的键值并执行 f 函数 | -|`func (h *ResponseHeader) DelAllCookies()` |删除所有 Cookie | -|`func (h *ResponseHeader) DelCookie(key string)` |删除响应头中键为 key 的 Cookie,若要删除来自客户端的 Cookie,请使用 `DelClientCookie` 函数 | -|`func (h *ResponseHeader) DelCookieBytes(key []byte)` |删除响应头中键为 key 的 Cookie,若要删除来自客户端的 Cookie,请使用 `DelClientCookieBytes` 函数 | -|`func (h *ResponseHeader) DelClientCookie(key string)` |删除来自客户端键为 key 的 Cookie | -|`func (h *ResponseHeader) DelClientCookieBytes(key []byte)` |删除来自客户端键为 key 的 Cookie | -|`func (h *ResponseHeader) SetConnectionClose(close bool)`|在响应头中设置 `Connection: close` 标志 | -|`func (h *ResponseHeader) ConnectionClose() bool` |判断是否包含 Connection: close | -|`func (h *ResponseHeader) ContentEncoding() []byte` |获取 Content-Encoding | -|`func (h *ResponseHeader) SetContentEncoding(contentEncoding string)` |设置 Content-Encoding | -|`func (h *ResponseHeader) SetContentEncodingBytes(contentEncoding []byte)` |设置 Content-Encoding | -|`func (h *ResponseHeader) SetCanonical(key, value []byte)` |设置 Header 键值,假设该键是规范形式 | -|`func (h *ResponseHeader) Server() []byte` |返回 Header 中 key 为 `Server` 的值 | -|`func (h *ResponseHeader) SetServerBytes(server []byte)` |设置 Header 中 key 为 Server 的值 | -|`func (h *ResponseHeader) MustSkipContentLength() bool` |判断是否有响应 body(HTTP/1.1 协议规定,响应状态码为 1xx、204、304 时没有响应 body) | -|`func (h *ResponseHeader) StatusCode() int` |获取响应状态码 | -|`func (h *ResponseHeader) SetStatusCode(statusCode int)`| 设置响应状态码 | -|`func (h *ResponseHeader) Len() int` |返回 Header 的数量 | -|`func (h *ResponseHeader) DisableNormalizing()` |禁用 Header 名字的规范化 (首字母和破折号后第一个字母大写) | -|`func (h *ResponseHeader) IsDisableNormalizing() bool` |是否禁用 Header 名字的规范化,默认不禁用 | -|`func (h *ResponseHeader) Trailer() *Trailer` |获取 Trailer | -|`func (h *ResponseHeader) SetProtocol(p string)` |设置协议名 | -|`func (h *ResponseHeader) GetProtocol() string` |获取协议名 | -|`func (h *ResponseHeader) Reset()`|重置响应头 | -|`func (h *ResponseHeader) ResetSkipNormalize()` |重置响应头,除了 `disableNormalizing` 状态 | -|`func (h *ResponseHeader) ResetConnectionClose()` |重置 connectionClose 标志为 false 并删除 Connection Header | +| 函数签名 | 说明 | +| :------------------------------------------------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `func (h *ResponseHeader) IsHTTP11() bool` | 判断是否是 `HTTP/1.1` 协议,true 表示是 `HTTP/1.1` 协议 | +| `func (h *ResponseHeader) SetHeaderLength(length int)` | 设置响应头的大小 | +| `func (h *ResponseHeader) GetHeaderLength()` | 获取响应头的大小 | +| `func (h *ResponseHeader) SetContentRange(startPos, endPos, contentLength int)` | 在响应头中设置 `Content-Range: bytes startPos-endPos/contentLength`,如 `Content-Range: bytes 1-5/10` | +| `func (h *ResponseHeader) NoDefaultContentType() bool` | 获取未指定 Content-Type 时的默认发送行为,false 表示发送默认 Content-Type 的值,true 表示不发送,默认 Content-Type 的值为 `text/plain; charset=utf-8` | +| `func (h *ResponseHeader) SetNoDefaultContentType(b bool)` | 设置未指定 Content-Type 时的默认发送行为,false 表示发送默认 Content-Type 的值,true 表示不发送,默认 Content-Type 的值为 `text/plain; charset=utf-8` | +| `func (h *ResponseHeader) SetContentType(contentType string)` | 设置 Content-Type | +| `func (h *ResponseHeader) ContentType() []byte` | 获取 Content-Type | +| `func (h *ResponseHeader) SetContentTypeBytes(contentType []byte)` | 设置 Content-Type | +| `func (h *ResponseHeader) ContentLength() int` | 获取 Content-Length,可以是负值,-1 表示 `Transfer-Encoding: chunked`,-2 表示 `Transfer-Encoding: identity` | +| `func (h *ResponseHeader) SetContentLength(contentLength int)` | 设置 Content-Length,可以是负值,-1 表示 `Transfer-Encoding: chunked`,-2 表示 `Transfer-Encoding: identity` | +| `func (h *ResponseHeader) SetContentLengthBytes(contentLength []byte)` | 设置 `[]byte` 类型的 Content-Length,可以是负值,-1 表示 `Transfer-Encoding: chunked`,-2 表示 `Transfer-Encoding: identity` | +| `func (h *ResponseHeader) CopyTo(dst *ResponseHeader)` | 返回响应头的副本,在对响应头存在竞争访问时可以使用 | +| `func (h *ResponseHeader) GetHeaders() []argsKV` | 以键值对的形式返回所有响应头 | +| `func (h *ResponseHeader) VisitAll(f func(key, value []byte))` | 遍历所有 Header 的键值并执行 f 函数 | +| `func (h *ResponseHeader) Get(key string) string` | 获取键为 key 的值,并发安全 | +| `func (h *ResponseHeader) GetAll(key string) []string` | 获取 `[]byte` 类型的键为 key 的所有值(用于获取存在相同 key 的多个值),并发安全 | +| `func (h *ResponseHeader) Peek(key string) []byte` | 获取 `[]byte` 类型的键为 key 的值,并发不安全,竞争访问时使用 `Get` | +| `func (h *ResponseHeader) PeekAll(key string) [][]byte` | 获取 `[]byte` 类型的键为 key 的所有值(用于获取存在相同 key 的多个值),并发不安全,竞争访问时使用 `GetAll` | +| `func (h *ResponseHeader) Set(key, value string)` | 设置 Header 键值,用于为同一个 Key 设置单个 Header | +| `func (h *ResponseHeader) SetBytesV(key string, value []byte)` | 设置 `[]byte` 类型的 Header 键值,用于为同一个 Key 设置单个 Header | +| `func (h *ResponseHeader) Add(key, value string)` | 设置 Header 键值,用于为同一个 Key 设置多个 Header,但 key 会覆盖以下 Header: Content-Type, Content-Length, Connection, Cookie, Transfer-Encoding, Host, User-Agent | +| `func (h *ResponseHeader) AddArgBytes(key, value []byte, noValue bool)` | 添加 Header 键值(与 `Add` 不同,key 一定不会被规范化且 key 为 Content-Type, Content-Length, Content-Encoding, Connection, Server, Set-Cookie, Transfer-Encoding 时不会做特殊处理) | +| `func (h *ResponseHeader) SetArgBytes(key, value []byte, noValue bool)` | 设置 Header 键值(与 `Set` 不同,key 一定不会被规范化且 key 为 Content-Type, Content-Length, Content-Encoding, Connection, Server, Set-Cookie, Transfer-Encoding 时不会做特殊处理) | +| `func (h *ResponseHeader) Del(key string)` | 删除 Header 中键为 key 的键值对 | +| `func (h *ResponseHeader) DelBytes(key []byte)` | 删除 Header 中键为 key 的键值对 | +| `func (h *ResponseHeader) AppendBytes(dst []byte) []byte` | 将完整的 Header 附加到 dst 中并返回 | +| `func (h *ResponseHeader) Header() []byte` | 获取 `[]byte` 类型的完整的 Header | +| `func (h *ResponseHeader) PeekLocation() []byte` | 返回 Header 中 key 为 `Location` 的值 | +| `func (h *ResponseHeader) Cookie(cookie *Cookie) bool` | 填充给定 cookie.Key 的 cookie,如果 cookie.Key 不存在则返回 false | +| `func (h *RequestHeader) FullCookie() []byte` | 以字节数组形式返回完整的 cookie | +| `func (h *ResponseHeader) SetCookie(cookie *Cookie)` | 设置 Cookie 的键值 | +| `func (h *ResponseHeader) VisitAllCookie(f func(key, value []byte))` | 遍历所有 Cookie 的键值并执行 f 函数 | +| `func (h *ResponseHeader) DelAllCookies()` | 删除所有 Cookie | +| `func (h *ResponseHeader) DelCookie(key string)` | 删除响应头中键为 key 的 Cookie,若要删除来自客户端的 Cookie,请使用 `DelClientCookie` 函数 | +| `func (h *ResponseHeader) DelCookieBytes(key []byte)` | 删除响应头中键为 key 的 Cookie,若要删除来自客户端的 Cookie,请使用 `DelClientCookieBytes` 函数 | +| `func (h *ResponseHeader) DelClientCookie(key string)` | 删除来自客户端键为 key 的 Cookie | +| `func (h *ResponseHeader) DelClientCookieBytes(key []byte)` | 删除来自客户端键为 key 的 Cookie | +| `func (h *ResponseHeader) SetConnectionClose(close bool)` | 在响应头中设置 `Connection: close` 标志 | +| `func (h *ResponseHeader) ConnectionClose() bool` | 判断是否包含 Connection: close | +| `func (h *ResponseHeader) ContentEncoding() []byte` | 获取 Content-Encoding | +| `func (h *ResponseHeader) SetContentEncoding(contentEncoding string)` | 设置 Content-Encoding | +| `func (h *ResponseHeader) SetContentEncodingBytes(contentEncoding []byte)` | 设置 Content-Encoding | +| `func (h *ResponseHeader) SetCanonical(key, value []byte)` | 设置 Header 键值,假设该键是规范形式 | +| `func (h *ResponseHeader) Server() []byte` | 返回 Header 中 key 为 `Server` 的值 | +| `func (h *ResponseHeader) SetServerBytes(server []byte)` | 设置 Header 中 key 为 Server 的值 | +| `func (h *ResponseHeader) MustSkipContentLength() bool` | 判断是否有响应 body(HTTP/1.1 协议规定,响应状态码为 1xx、204、304 时没有响应 body) | +| `func (h *ResponseHeader) StatusCode() int` | 获取响应状态码 | +| `func (h *ResponseHeader) SetStatusCode(statusCode int)` | 设置响应状态码 | +| `func (h *ResponseHeader) Len() int` | 返回 Header 的数量 | +| `func (h *ResponseHeader) DisableNormalizing()` | 禁用 Header 名字的规范化 (首字母和破折号后第一个字母大写) | +| `func (h *ResponseHeader) IsDisableNormalizing() bool` | 是否禁用 Header 名字的规范化,默认不禁用 | +| `func (h *ResponseHeader) Trailer() *Trailer` | 获取 Trailer | +| `func (h *ResponseHeader) SetProtocol(p string)` | 设置协议名 | +| `func (h *ResponseHeader) GetProtocol() string` | 获取协议名 | +| `func (h *ResponseHeader) Reset()` | 重置响应头 | +| `func (h *ResponseHeader) ResetSkipNormalize()` | 重置响应头,除了 `disableNormalizing` 状态 | +| `func (h *ResponseHeader) ResetConnectionClose()` | 重置 connectionClose 标志为 false 并删除 Connection Header | ## 渲染 @@ -610,8 +611,8 @@ h.GET("/user", func(c context.Context, ctx *app.RequestContext) { ## 其他 ```go -func (ctx *RequestContext) Flush() error -func (ctx *RequestContext) GetResponse() (dst *protocol.Response) +func (ctx *RequestContext) Flush() error +func (ctx *RequestContext) GetResponse() (dst *protocol.Response) ``` ### Flush @@ -621,7 +622,7 @@ func (ctx *RequestContext) GetResponse() (dst *protocol.Response) 函数签名: ```go -func (ctx *RequestContext) Flush() error +func (ctx *RequestContext) Flush() error ``` ### GetResponse diff --git a/content/zh/docs/hertz/tutorials/basic-feature/engine.md b/content/zh/docs/hertz/tutorials/basic-feature/engine.md index d702b362bc..b8510b5f07 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/engine.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/engine.md @@ -5,13 +5,12 @@ weight: 1 description: > --- - `server.Hertz` 是 `Hertz` 的核心类型,它由 `route.Engine` 以及 `signalWaiter` 组成,`Hertz` 服务器的启动、路由注册、中间件注册以及退出等重要方法均包含在 `server.Hertz` 中。以下是 `server.Hertz` 的定义: ```go type Hertz struct { -    *route.Engine -    // 用于接收信号以实现优雅退出 +    *route.Engine +    // 用于接收信号以实现优雅退出     signalWaiter func (err chan error) error } ``` @@ -20,48 +19,48 @@ type Hertz struct { ## 配置 -| 配置项 | 默认值 | 说明 | -| :---- | :---- | :---- | -| WithTransport | network.NewTransporter | 更换底层 transport | -| WithHostPorts | `:8888` | 指定监听的地址和端口 | -| WithKeepAliveTimeout | 1min | tcp 长连接保活时间,一般情况下不用修改,更应该关注 idleTimeout | -| WithReadTimeout | 3min | 底层读取数据超时时间 | -| WithIdleTimeout | 3min | 长连接请求链接空闲超时时间 | -| WithMaxRequestBodySize | 4 * 1024 * 1024 | 配置最大的请求体大小 | -| WithRedirectTrailingSlash | true | 自动根据末尾的 / 转发,例如:如果 router 只有 /foo/,那么 /foo 会重定向到 /foo/ ;如果只有 /foo,那么 /foo/ 会重定向到 /foo | -| WithRemoveExtraSlash | false | RemoveExtraSlash 当有额外的 / 时也可以当作参数。如:user/:name,如果开启该选项 user//xiaoming 也可匹配上参数 | -| WithUnescapePathValues | true | 如果开启,请求路径会被自动转义(eg. '%2F' -> '/')。如果 UseRawPath 为 false(默认情况),则 UnescapePathValues 实际上为 true,因为 .URI().Path() 将被使用,它已经是转义后的。设置该参数为 false,需要配合 WithUseRawPath(true) | -| WithUseRawPath | false | 如果开启,会使用原始 path 进行路由匹配 | -| WithHandleMethodNotAllowed | false | 如果开启,当当前路径不能被匹配上时,server 会去检查其他方法是否注册了当前路径的路由,如果存在则会响应"Method Not Allowed",并返回状态码 405; 如果没有,则会用 NotFound 的 handler 进行处理 | -| WithDisablePreParseMultipartForm | false | 如果开启,则不会预处理 multipart form。可以通过 ctx.Request.Body() 获取到 body 后由用户处理 | -| WithStreamBody | false | 如果开启,则会使用流式处理 body | -| WithNetwork | "tcp" | 设置网络协议,可选:tcp,udp,unix(unix domain socket),默认为 tcp | -| WithExitWaitTime | 5s | 设置优雅退出时间。Server 会停止建立新的连接,并对关闭后的每一个请求设置 Connection: Close 的 header,当到达设定的时间关闭 Server。当所有连接已经关闭时,Server 可以提前关闭 | -| WithTLS | nil | 配置 server tls 能力,详情可见 [TLS](/zh/docs/hertz/tutorials/basic-feature/protocol/tls/) | -| WithListenConfig | nil | 设置监听器配置,可用于设置是否允许 reuse port 等 | -| WithALPN | false | 是否开启 ALPN | -| WithTracer | []interface{}{} | 注入 tracer 实现,如不注入 Tracer 实现,默认关闭 | -| WithTraceLevel | LevelDetailed | 设置 trace level | -| WithWriteTimeout | 无限长 | 写入数据超时时间 | -| WithRedirectFixedPath | false | 如果开启,当当前请求路径不能匹配上时,server 会尝试修复请求路径并重新进行匹配,如果成功匹配并且为 GET 请求则会返回状态码 301 进行重定向,其他请求方式返回 308 进行重定向 | -| WithBasePath | `/` | 设置基本路径,前缀和后缀必须为 `/` | -| WithMaxKeepBodySize | 4 * 1024 * 1024 | 设置回收时保留的请求体和响应体的最大大小。单位:字节 | -| WithGetOnly | false | 如果开启则只接受 GET 请求 | -| WithKeepAlive | true | 如果开启则使用 HTTP 长连接 | -| WithAltTransport | network.NewTransporter | 设置备用 transport | -| WithH2C | false | 设置是否开启 H2C | -| WithReadBufferSize | 4 * 1024 | 设置读缓冲区大小,同时限制 HTTP header 大小 | -| WithRegistry | registry.NoopRegistry, nil | 设置注册中心配置,服务注册信息 | -| WithAutoReloadRender | false, 0 | 设置自动重载渲染配置 | -| WithDisablePrintRoute | false | 设置是否禁用 debugPrintRoute | -| WithOnAccept | nil | 设置在 netpoll 中当一个连接被接受但不能接收数据时的回调函数,在 go net 中在转换 TLS 连接之前被调用 | -| WithOnConnect | nil | 设置 onConnect 函数。它可以接收来自 netpoll 连接的数据。在 go net 中,它将在转换 TLS 连接后被调用 | -| WithDisableHeaderNamesNormalizing|false|设置是否禁用 Request 和 Response Header 名字的规范化 (首字母和破折号后第一个字母大写)| +| 配置项 | 默认值 | 说明 | +| :-------------------------------- | :------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| WithTransport | network.NewTransporter | 更换底层 transport | +| WithHostPorts | `:8888` | 指定监听的地址和端口 | +| WithKeepAliveTimeout | 1min | tcp 长连接保活时间,一般情况下不用修改,更应该关注 idleTimeout | +| WithReadTimeout | 3min | 底层读取数据超时时间 | +| WithIdleTimeout | 3min | 长连接请求链接空闲超时时间 | +| WithMaxRequestBodySize | 4 _ 1024 _ 1024 | 配置最大的请求体大小 | +| WithRedirectTrailingSlash | true | 自动根据末尾的 / 转发,例如:如果 router 只有 /foo/,那么 /foo 会重定向到 /foo/ ;如果只有 /foo,那么 /foo/ 会重定向到 /foo | +| WithRemoveExtraSlash | false | RemoveExtraSlash 当有额外的 / 时也可以当作参数。如:user/:name,如果开启该选项 user//xiaoming 也可匹配上参数 | +| WithUnescapePathValues | true | 如果开启,请求路径会被自动转义(eg. '%2F' -> '/')。如果 UseRawPath 为 false(默认情况),则 UnescapePathValues 实际上为 true,因为 .URI().Path() 将被使用,它已经是转义后的。设置该参数为 false,需要配合 WithUseRawPath(true) | +| WithUseRawPath | false | 如果开启,会使用原始 path 进行路由匹配 | +| WithHandleMethodNotAllowed | false | 如果开启,当当前路径不能被匹配上时,server 会去检查其他方法是否注册了当前路径的路由,如果存在则会响应"Method Not Allowed",并返回状态码 405; 如果没有,则会用 NotFound 的 handler 进行处理 | +| WithDisablePreParseMultipartForm | false | 如果开启,则不会预处理 multipart form。可以通过 ctx.Request.Body() 获取到 body 后由用户处理 | +| WithStreamBody | false | 如果开启,则会使用流式处理 body | +| WithNetwork | "tcp" | 设置网络协议,可选:tcp,udp,unix(unix domain socket),默认为 tcp | +| WithExitWaitTime | 5s | 设置优雅退出时间。Server 会停止建立新的连接,并对关闭后的每一个请求设置 Connection: Close 的 header,当到达设定的时间关闭 Server。当所有连接已经关闭时,Server 可以提前关闭 | +| WithTLS | nil | 配置 server tls 能力,详情可见 [TLS](/zh/docs/hertz/tutorials/basic-feature/protocol/tls/) | +| WithListenConfig | nil | 设置监听器配置,可用于设置是否允许 reuse port 等 | +| WithALPN | false | 是否开启 ALPN | +| WithTracer | []interface{}{} | 注入 tracer 实现,如不注入 Tracer 实现,默认关闭 | +| WithTraceLevel | LevelDetailed | 设置 trace level | +| WithWriteTimeout | 无限长 | 写入数据超时时间 | +| WithRedirectFixedPath | false | 如果开启,当当前请求路径不能匹配上时,server 会尝试修复请求路径并重新进行匹配,如果成功匹配并且为 GET 请求则会返回状态码 301 进行重定向,其他请求方式返回 308 进行重定向 | +| WithBasePath | `/` | 设置基本路径,前缀和后缀必须为 `/` | +| WithMaxKeepBodySize | 4 _ 1024 _ 1024 | 设置回收时保留的请求体和响应体的最大大小。单位:字节 | +| WithGetOnly | false | 如果开启则只接受 GET 请求 | +| WithKeepAlive | true | 如果开启则使用 HTTP 长连接 | +| WithAltTransport | network.NewTransporter | 设置备用 transport | +| WithH2C | false | 设置是否开启 H2C | +| WithReadBufferSize | 4 \* 1024 | 设置读缓冲区大小,同时限制 HTTP header 大小 | +| WithRegistry | registry.NoopRegistry, nil | 设置注册中心配置,服务注册信息 | +| WithAutoReloadRender | false, 0 | 设置自动重载渲染配置 | +| WithDisablePrintRoute | false | 设置是否禁用 debugPrintRoute | +| WithOnAccept | nil | 设置在 netpoll 中当一个连接被接受但不能接收数据时的回调函数,在 go net 中在转换 TLS 连接之前被调用 | +| WithOnConnect | nil | 设置 onConnect 函数。它可以接收来自 netpoll 连接的数据。在 go net 中,它将在转换 TLS 连接后被调用 | +| WithDisableHeaderNamesNormalizing | false | 设置是否禁用 Request 和 Response Header 名字的规范化 (首字母和破折号后第一个字母大写) | Server Connection 数量限制: -* 如果是使用标准网络库,无此限制 -* 如果是使用 netpoll,最大连接数为 10000 +- 如果是使用标准网络库,无此限制 +- 如果是使用 netpoll,最大连接数为 10000 (这个是 netpoll 底层使用的 [gopool](https://github.com/bytedance/gopkg/blob/b9c1c36b51a6837cef4c2223e11522e3a647460c/util/gopool/gopool.go#L46) )控制的,修改方式也很简单,调用 gopool 提供的函数即可:`gopool.SetCap(xxx)`(main.go 中调用一次即可)。 @@ -287,130 +286,130 @@ Hertz Server 支持流式写入响应。 提供了两种方式: 1. 用户在 handler 中通过 `ctx.SetBodyStream` 函数传入一个 `io.Reader`,然后按与示例代码(利用 channel 控制数据分块及读写顺序)类似的方式分块读写数据。**注意,数据需异步写入。** - - 若用户事先知道传输数据的总长度,可以在 `ctx.SetBodyStream` 函数中传入该长度进行流式写,示例代码如 `/streamWrite1`。 - - 若用户事先不知道传输数据的总长度,可以在 `ctx.SetBodyStream` 函数中传入 -1 以 `Transfer-Encoding: chunked` 的方式进行流式写,示例代码如 `/streamWrite2`。 - - 示例代码: - - ```go - func main() { - h := server.Default(server.WithHostPorts("127.0.0.1:8080"), server.WithStreamBody(true), server.WithTransport(standard.NewTransporter)) - - h.GET("/streamWrite1", func(c context.Context, ctx *app.RequestContext) { - rw := newChunkReader() - line := []byte("line\r\n") - ctx.SetBodyStream(rw, 500*len(line)) - - go func() { - for i := 1; i <= 500; i++ { - // For each streaming_write, the upload_file prints - rw.Write(line) - fmt.Println(i) - time.Sleep(10 * time.Millisecond) - } - rw.Close() - }() - - go func() { - <-ctx.Finished() - fmt.Println("request process end") - }() - }) - - h.GET("/streamWrite2", func(c context.Context, ctx *app.RequestContext) { - rw := newChunkReader() - // Content-Length may be negative: - // -1 means Transfer-Encoding: chunked. - ctx.SetBodyStream(rw, -1) - - go func() { - for i := 1; i < 1000; i++ { - // For each streaming_write, the upload_file prints - rw.Write([]byte(fmt.Sprintf("===%d===\n", i))) - fmt.Println(i) - time.Sleep(100 * time.Millisecond) - } - rw.Close() - }() - - go func() { - <-ctx.Finished() - fmt.Println("request process end") - }() - }) - - h.Spin() - } - - type ChunkReader struct { - rw bytes.Buffer - w2r chan struct{} - r2w chan struct{} - } - - func newChunkReader() *ChunkReader { - var rw bytes.Buffer - w2r := make(chan struct{}) - r2w := make(chan struct{}) - cr := &ChunkReader{rw, w2r, r2w} - return cr - } - - var closeOnce = new(sync.Once) - - func (cr *ChunkReader) Read(p []byte) (n int, err error) { - for { - _, ok := <-cr.w2r - if !ok { - closeOnce.Do(func() { - close(cr.r2w) - }) - n, err = cr.rw.Read(p) - return - } - - n, err = cr.rw.Read(p) - - cr.r2w <- struct{}{} - - if n == 0 { - continue - } - return - } - } - - func (cr *ChunkReader) Write(p []byte) (n int, err error) { - n, err = cr.rw.Write(p) - cr.w2r <- struct{}{} - <-cr.r2w - return - } - - func (cr *ChunkReader) Close() { - close(cr.w2r) - } - - ``` - -2. 用户可以在 handler 中使用 `pkg/protocol/http1/resp/writer` 下提供的 `NewChunkedBodyWriter` 方法劫持 response 的 writer,然后使用 `ctx.Write` 函数将分块数据写入 Body 并将分块数据使用 `ctx.Flush` 函数立即发送给客户端。 - - 示例代码: - - ```go - h.GET("/flush/chunk", func(c context.Context, ctx *app.RequestContext) { - // Hijack the writer of response - ctx.Response.HijackWriter(resp.NewChunkedBodyWriter(&ctx.Response, ctx.GetWriter())) - - for i := 0; i < 10; i++ { - ctx.Write([]byte(fmt.Sprintf("chunk %d: %s", i, strings.Repeat("hi~", i)))) // nolint: errcheck - ctx.Flush() // nolint: errcheck - time.Sleep(200 * time.Millisecond) - } - }) - ``` + + 若用户事先知道传输数据的总长度,可以在 `ctx.SetBodyStream` 函数中传入该长度进行流式写,示例代码如 `/streamWrite1`。 + + 若用户事先不知道传输数据的总长度,可以在 `ctx.SetBodyStream` 函数中传入 -1 以 `Transfer-Encoding: chunked` 的方式进行流式写,示例代码如 `/streamWrite2`。 + + 示例代码: + + ```go + func main() { + h := server.Default(server.WithHostPorts("127.0.0.1:8080"), server.WithStreamBody(true), server.WithTransport(standard.NewTransporter)) + + h.GET("/streamWrite1", func(c context.Context, ctx *app.RequestContext) { + rw := newChunkReader() + line := []byte("line\r\n") + ctx.SetBodyStream(rw, 500*len(line)) + + go func() { + for i := 1; i <= 500; i++ { + // For each streaming_write, the upload_file prints + rw.Write(line) + fmt.Println(i) + time.Sleep(10 * time.Millisecond) + } + rw.Close() + }() + + go func() { + <-ctx.Finished() + fmt.Println("request process end") + }() + }) + + h.GET("/streamWrite2", func(c context.Context, ctx *app.RequestContext) { + rw := newChunkReader() + // Content-Length may be negative: + // -1 means Transfer-Encoding: chunked. + ctx.SetBodyStream(rw, -1) + + go func() { + for i := 1; i < 1000; i++ { + // For each streaming_write, the upload_file prints + rw.Write([]byte(fmt.Sprintf("===%d===\n", i))) + fmt.Println(i) + time.Sleep(100 * time.Millisecond) + } + rw.Close() + }() + + go func() { + <-ctx.Finished() + fmt.Println("request process end") + }() + }) + + h.Spin() + } + + type ChunkReader struct { + rw bytes.Buffer + w2r chan struct{} + r2w chan struct{} + } + + func newChunkReader() *ChunkReader { + var rw bytes.Buffer + w2r := make(chan struct{}) + r2w := make(chan struct{}) + cr := &ChunkReader{rw, w2r, r2w} + return cr + } + + var closeOnce = new(sync.Once) + + func (cr *ChunkReader) Read(p []byte) (n int, err error) { + for { + _, ok := <-cr.w2r + if !ok { + closeOnce.Do(func() { + close(cr.r2w) + }) + n, err = cr.rw.Read(p) + return + } + + n, err = cr.rw.Read(p) + + cr.r2w <- struct{}{} + + if n == 0 { + continue + } + return + } + } + + func (cr *ChunkReader) Write(p []byte) (n int, err error) { + n, err = cr.rw.Write(p) + cr.w2r <- struct{}{} + <-cr.r2w + return + } + + func (cr *ChunkReader) Close() { + close(cr.w2r) + } + + ``` + +2. 用户可以在 handler 中使用 `pkg/protocol/http1/resp/writer` 下提供的 `NewChunkedBodyWriter` 方法劫持 response 的 writer,然后使用 `ctx.Write` 函数将分块数据写入 Body 并将分块数据使用 `ctx.Flush` 函数立即发送给客户端。 + + 示例代码: + + ```go + h.GET("/flush/chunk", func(c context.Context, ctx *app.RequestContext) { + // Hijack the writer of response + ctx.Response.HijackWriter(resp.NewChunkedBodyWriter(&ctx.Response, ctx.GetWriter())) + + for i := 0; i < 10; i++ { + ctx.Write([]byte(fmt.Sprintf("chunk %d: %s", i, strings.Repeat("hi~", i)))) // nolint: errcheck + ctx.Flush() // nolint: errcheck + time.Sleep(200 * time.Millisecond) + } + }) + ``` **这两种方式的区别:第一种在执行完 handler 逻辑后再将数据按分块发送给客户端,第二种在 handler 逻辑中就可以将分块数据发送出去。** @@ -454,7 +453,7 @@ Hertz 提供了全局的 Hook 注入能力,用于在服务触发启动后和 用于设置当程序发生 panic 时的处理函数,默认为 `nil`。 ->注意:如果同时设置了 `PanicHandler` 和 `Recovery` 中间件,则 `Recovery` 中间件会覆盖 `PanicHandler` 的处理逻辑。 +> 注意:如果同时设置了 `PanicHandler` 和 `Recovery` 中间件,则 `Recovery` 中间件会覆盖 `PanicHandler` 的处理逻辑。 示例代码: @@ -568,7 +567,7 @@ tName := h.GetTransporterName() `SetTransporter` 用于设置网络库。 ->注意:`SetTransporter` 只设置 Engine 的全局默认值,所以在初始化 Engine 时使用 `WithTransporter` 来设置网络库会覆盖掉 `SetTransporter` 的设置。 +> 注意:`SetTransporter` 只设置 Engine 的全局默认值,所以在初始化 Engine 时使用 `WithTransporter` 来设置网络库会覆盖掉 `SetTransporter` 的设置。 函数签名: diff --git a/content/zh/docs/hertz/tutorials/basic-feature/error-handle.md b/content/zh/docs/hertz/tutorials/basic-feature/error-handle.md index 1bc2026464..450269fc39 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/error-handle.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/error-handle.md @@ -5,7 +5,6 @@ date: 2022-05-23 weight: 10 keywords: ["错误处理", "自定义错误"] description: "Hertz 提供的错误处理功能。" - --- ## 错误 @@ -80,14 +79,14 @@ func NewPrivatef(format string, v ...interface{}) *Error { ### 相关方法 -| 函数签名 | 描述 | -| -------------------------------- | ------------------------------------------------ | -| SetType(flags ErrorType) *Error | 将 `Error` 的 `ErrorType` 设置为给定的 `flags` | -| Error() string | 实现标准 `error` 接口 | -| Unwrap() error | 抛出错误 | -| SetMeta(data interface{}) *Error | 设置元数据 | -| IsType(flags ErrorType) bool | 判断 `Error` 的 `ErrorType` 是否为给定的 `flags` | -| JSON() interface{} | 将错误转换为 `json` 对象 | +| 函数签名 | 描述 | +| --------------------------------- | ------------------------------------------------ | +| SetType(flags ErrorType) \*Error | 将 `Error` 的 `ErrorType` 设置为给定的 `flags` | +| Error() string | 实现标准 `error` 接口 | +| Unwrap() error | 抛出错误 | +| SetMeta(data interface{}) \*Error | 设置元数据 | +| IsType(flags ErrorType) bool | 判断 `Error` 的 `ErrorType` 是否为给定的 `flags` | +| JSON() interface{} | 将错误转换为 `json` 对象 | ## ErrorChain @@ -100,8 +99,8 @@ func NewPrivatef(format string, v ...interface{}) *Error { | String() string | 返回一个可读性强的文本用于展示所有错误 | | Errors() []string | 将错误链转换为标准错误数组 | | ByType(typ ErrorType) ErrorChain | 按给定的错误类型返回对应的子错误链 | -| Last() *Error | 返回最后(最新)的一个错误 | -| JSON() interface{} | 将所有错误转换为 `json` 对象 | +| Last() \*Error | 返回最后(最新)的一个错误 | +| JSON() interface{} | 将所有错误转换为 `json` 对象 | ### 如何使用 diff --git a/content/zh/docs/hertz/tutorials/basic-feature/graceful-shutdown.md b/content/zh/docs/hertz/tutorials/basic-feature/graceful-shutdown.md index 33a34df18b..bc0380b1fd 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/graceful-shutdown.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/graceful-shutdown.md @@ -4,7 +4,6 @@ date: 2022-05-23 weight: 11 keywords: ["优雅退出"] description: "Hertz 停止服务时提供的优雅退出功能。" - --- Hertz 支持优雅退出,优雅退出过程如下: diff --git a/content/zh/docs/hertz/tutorials/basic-feature/hooks.md b/content/zh/docs/hertz/tutorials/basic-feature/hooks.md index 45973350a2..7845fb8b73 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/hooks.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/hooks.md @@ -4,7 +4,6 @@ date: 2022-10-16 weight: 14 keywords: ["Hooks", "StartHook", "ShutdownHook", "OnAccept", "OnConnect"] description: "Hertz 提供的钩子函数功能。" - --- **钩子函数**(Hooks)是一个通用的概念,表示某事件触发时所伴随的操作。 diff --git a/content/zh/docs/hertz/tutorials/basic-feature/json.md b/content/zh/docs/hertz/tutorials/basic-feature/json.md index 9a06050380..bfbd7f3be4 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/json.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/json.md @@ -26,7 +26,7 @@ Hertz 默认集成并使用 [Sonic](https://github.com/bytedance/sonic) 用于 Hertz 支持条件编译来控制实际使用的 json 库,你可以通过 `-tags stdjson` 来选择使用标准库。 ```go -go build -tags stdjson +go build -tags stdjson ``` ## Sonic 相关问题 diff --git a/content/zh/docs/hertz/tutorials/basic-feature/middleware/_index.md b/content/zh/docs/hertz/tutorials/basic-feature/middleware/_index.md index 07139072f4..6903021ef0 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/middleware/_index.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/middleware/_index.md @@ -4,7 +4,6 @@ date: 2022-05-20 weight: 6 keywords: ["中间件", "服务端中间件", "客户端中间件", "路由级别"] description: "中间件概览。" - --- Hertz中间件的种类是多种多样的,简单分为两大类: @@ -16,9 +15,9 @@ Hertz中间件的种类是多种多样的,简单分为两大类: Hertz 服务端中间件是 HTTP 请求-响应周期中的一个函数,提供了一种方便的机制来检查和过滤进入应用程序的 HTTP 请求, 例如记录每个请求或者启用CORS。 -|![middleware](/img/docs/hertz_middleware.png )| -|:--:| -|图1:中间件调用链| +| ![middleware](/img/docs/hertz_middleware.png) | +| :-------------------------------------------: | +| 图1:中间件调用链 | 中间件可以在请求更深入地传递到业务逻辑之前或之后执行: @@ -243,4 +242,4 @@ func main() { - `c.Abort()`:终止后续调用 - `c.AbortWithMsg(msg string, statusCode int)`:终止后续调用,并设置 response 中 body 和状态码 -- `c.AbortWithStatus(code int)`:终止后续调用,并设置状态码 \ No newline at end of file +- `c.AbortWithStatus(code int)`:终止后续调用,并设置状态码 diff --git a/content/zh/docs/hertz/tutorials/basic-feature/middleware/basic-auth.md b/content/zh/docs/hertz/tutorials/basic-feature/middleware/basic-auth.md index a9b49a99b7..2e52d02173 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/middleware/basic-auth.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/middleware/basic-auth.md @@ -4,7 +4,6 @@ date: 2022-10-13 weight: 2 keywords: ["HTTP", "基本认证"] description: "Hertz 提供了 basic auth 的实现。" - --- 在 HTTP 中,基本认证(Basic access authentication)是一种用来允许网页浏览器或其他客户端程序在请求时提供用户名和密码形式的身份凭证的一种登录验证方式。 @@ -56,11 +55,11 @@ Hertz 通过使用中间件可以实现让网页浏览器或其他客户端程 **注意:** `BasicAuth` 是对 `BasicAuthForRealm` 的封装并提供了默认配置项。 -| 参数 | 介绍 | -|----------|--------------------------------------------------------| +| 参数 | 介绍 | +| -------- | ---------------------------------------------------------------------------- | | accounts | `Accounts` 被定义为 `map[string]string` 类型,以键值对的形式存储用户名和密码 | -| realm | 安全域字符串,默认值为 `Authorization Required` | -| userKey | 认证通过后在上下文中设置的用户名所对应的键值,默认值为 `user` | +| realm | 安全域字符串,默认值为 `Authorization Required` | +| userKey | 认证通过后在上下文中设置的用户名所对应的键值,默认值为 `user` | ### BasicAuth diff --git a/content/zh/docs/hertz/tutorials/basic-feature/middleware/cache.md b/content/zh/docs/hertz/tutorials/basic-feature/middleware/cache.md index d395d6498b..eb1dc14a7f 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/middleware/cache.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/middleware/cache.md @@ -4,7 +4,6 @@ date: 2023-02-25 weight: 15 keywords: ["HTTP 响应", "缓存"] description: "Hertz 提供了对 cache 的适配,支持 multi-backend。" - --- cache 是一个用于缓存 HTTP 响应的中间件,开启后有助于提高服务器的并发访问能力。Hertz 也提供了对 cache 的 [适配](https://github.com/hertz-contrib/cache),支持 multi-backend,参考了 [gin-cache](https://github.com/chenyahui/gin-cache) 的实现。 @@ -192,16 +191,16 @@ func main() { ## 配置 -| 配置 | 默认值 | 介绍 | -| ----------------------------- | ------ | ---------------------------------------------- | -| WithOnHitCache | nil | 用于设置缓存命中的回调函数 | -| WithOnMissCache | nil | 用于设置缓存未命中的回调函数 | -| WithBeforeReplyWithCache | nil | 用于设置返回缓存响应前的回调函数 | -| WithOnShareSingleFlight | nil | 用于设置请求共享 SingleFlight 结果时的回调函数 | +| 配置 | 默认值 | 介绍 | +| ----------------------------- | ------ | -------------------------------------------------------------------------------------------- | +| WithOnHitCache | nil | 用于设置缓存命中的回调函数 | +| WithOnMissCache | nil | 用于设置缓存未命中的回调函数 | +| WithBeforeReplyWithCache | nil | 用于设置返回缓存响应前的回调函数 | +| WithOnShareSingleFlight | nil | 用于设置请求共享 SingleFlight 结果时的回调函数 | | WithSingleFlightForgetTimeout | 0 | 设置 SingleFlight 的超时时间,以控制并发操作的行为,确保请求在一定时间内被处理或者超时被取消 | -| WithPrefixKey | "" | 用于设置缓存响应 Key 的前缀 | -| WithoutHeader | false | 用于设置是否需要缓存响应头 | -| WithCacheStrategyByRequest | nil | 用于设置自定义的缓存策略 | +| WithPrefixKey | "" | 用于设置缓存响应 Key 的前缀 | +| WithoutHeader | false | 用于设置是否需要缓存响应头 | +| WithCacheStrategyByRequest | nil | 用于设置自定义的缓存策略 | ### WithCacheStrategyByRequest @@ -235,7 +234,7 @@ func main() { h.GET("/hello", func(ctx context.Context, c *app.RequestContext) { c.String(http.StatusOK, "hello world") }) - + h.Spin() } ``` @@ -396,7 +395,7 @@ func main() { h.GET("/hello", func(ctx context.Context, c *app.RequestContext) { c.String(http.StatusOK, "hello world") }) - + h.Spin() } ``` @@ -438,7 +437,7 @@ func main() { h.GET("/hello", func(ctx context.Context, c *app.RequestContext) { c.String(http.StatusOK, "hello world") }) - + h.Spin() } ``` diff --git a/content/zh/docs/hertz/tutorials/basic-feature/middleware/casbin.md b/content/zh/docs/hertz/tutorials/basic-feature/middleware/casbin.md index bb420c0ce6..a116a7f42f 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/middleware/casbin.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/middleware/casbin.md @@ -30,7 +30,7 @@ package main import ( "context" "log" - + "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/hertz-contrib/casbin" @@ -40,7 +40,7 @@ import ( func main() { h := server.Default() - + // 使用 session 存储用户信息. store := cookie.NewStore([]byte("secret")) h.Use(sessions.New("session", store)) @@ -48,11 +48,11 @@ func main() { if err != nil { log.Fatal(err) } - + h.POST("/login", func(ctx context.Context, c *app.RequestContext) { // 校验用户名和密码. // ... - + // 存储用户名 (casbin 访问实体) session := sessions.Default(c) session.Set("name", "alice") @@ -62,15 +62,15 @@ func main() { } c.String(200, "you login successfully") }) - + h.GET("/book", auth.RequiresPermissions("book:read", casbin.WithLogic(casbin.AND)), func(ctx context.Context, c *app.RequestContext) { c.String(200, "you read the book successfully") }) - + h.POST("/book", auth.RequiresRoles("user", casbin.WithLogic(casbin.AND)), func(ctx context.Context, c *app.RequestContext) { c.String(200, "you posted a book successfully") }) - + h.Spin() } @@ -158,7 +158,7 @@ func main() { if err != nil{ log.Fatal(err) } - + casbinMiddleware, err := casbin.NewCasbinMiddlewareFromEnforcer(enforcer, exampleLookupHandler) if err != nil { log.Fatal(err) @@ -183,27 +183,27 @@ func (m *Middleware) exampleMiddlwareMethod(expression string, opts ...Option) a - **expression** - 表达式含有一个或多个变量,变量之间用空格分隔,表达式的具体格式与 `Logic`(见后文 `选项说明`)相关, + 表达式含有一个或多个变量,变量之间用空格分隔,表达式的具体格式与 `Logic`(见后文 `选项说明`)相关, - 表达式的计算最终值为 **True** or **False**,**True** 则代表通过鉴权中间件,**False** 则代表没有通过鉴权中间件, + 表达式的计算最终值为 **True** or **False**,**True** 则代表通过鉴权中间件,**False** 则代表没有通过鉴权中间件, - 如 `Logic` 为 **AND** or **OR**,则格式为: + 如 `Logic` 为 **AND** or **OR**,则格式为: - `"var1 var2 var3 var4"`,比如 `"book:read book:write"` + `"var1 var2 var3 var4"`,比如 `"book:read book:write"` - 如 `Logic` 为 **CUSTOM**,则格式为: + 如 `Logic` 为 **CUSTOM**,则格式为: - `"var1 opr1 var2 opr2 var3"`,比如 `"book:read && book:write || book:all"` + `"var1 opr1 var2 opr2 var3"`,比如 `"book:read && book:write || book:all"` - **opts** - | 选项 | 介绍 | 默认值 | - | ------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ | - | `WithLogic` | `Logic` 是在 `expression` 中的逻辑操作 (**AND**/**OR**/**CUSTOM**) | `AND` | - | `WithPermissionParser` | `PermissionParserFunc` 是用于解析 `expression` 中变量得出 `obj` 和 `act` 的函数 | `PermissionParserWithSeparator(":")` | - | `WithPermissionParserSeparator` | `PermissionParserSeparator` 是用于设置 `expression` 中变量内部的分隔符 | `:` | - | `WithUnauthorized` | `Unauthorized` 用于定义未通过授权中间件时的响应体(找不到访问实体) | `func(ctx context.Context, c *app.RequestContext) { c.AbortWithStatus(consts.StatusUnauthorized) }` | - | `WithForbidden` | `Forbidden` 用于定义访问到禁止访问资源的响应体(访问实体没有相应权限) | `func(ctx context.Context, c *app.RequestContext) { c.AbortWithStatus(consts.StatusForbidden) }` | + | 选项 | 介绍 | 默认值 | + | ------------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | + | `WithLogic` | `Logic` 是在 `expression` 中的逻辑操作 (**AND**/**OR**/**CUSTOM**) | `AND` | + | `WithPermissionParser` | `PermissionParserFunc` 是用于解析 `expression` 中变量得出 `obj` 和 `act` 的函数 | `PermissionParserWithSeparator(":")` | + | `WithPermissionParserSeparator` | `PermissionParserSeparator` 是用于设置 `expression` 中变量内部的分隔符 | `:` | + | `WithUnauthorized` | `Unauthorized` 用于定义未通过授权中间件时的响应体(找不到访问实体) | `func(ctx context.Context, c *app.RequestContext) { c.AbortWithStatus(consts.StatusUnauthorized) }` | + | `WithForbidden` | `Forbidden` 用于定义访问到禁止访问资源的响应体(访问实体没有相应权限) | `func(ctx context.Context, c *app.RequestContext) { c.AbortWithStatus(consts.StatusForbidden) }` | #### RequiresPermissions @@ -250,19 +250,19 @@ func (m *Middleware) RequiresPermissions(expression string, opts ...Option) app. func main(){ ... h := server.Default() - + m, err := casbin.NewCasbinMiddleware("example/config/model.conf", "example/config/policy.csv", subjectFromSession) if err != nil { log.Fatal(err) } - + h.GET("/book", m.RequiresPermissions("book:read"), // 通过 func(ctx context.Context, c *app.RequestContext) { c.String(200, "you read the book successfully") }, ) - + h.GET("/book", m.RequiresPermissions("book:read book:write"), // 不通过 func(ctx context.Context, c *app.RequestContext) { @@ -293,26 +293,26 @@ func (m *Middleware) RequiresRoles(expression string, opts ...Option) app.Handle func main(){ ... h := server.Default() - + m, err := casbin.NewCasbinMiddleware("example/config/model.conf", "example/config/policy.csv", subjectFromSession) if err != nil { log.Fatal(err) } - + h.POST("/book", auth.RequiresRoles("user"), // 通过 func(ctx context.Context, c *app.RequestContext) { c.String(200, "you posted a book successfully") }, ) - + h.POST("/book", auth.RequiresRoles("user reader"), // 通过 func(ctx context.Context, c *app.RequestContext) { c.String(200, "you posted a book successfully") }, ) - + h.POST("/book", auth.RequiresRoles("user reader admin"), // 不通过 func(ctx context.Context, c *app.RequestContext) { @@ -349,7 +349,7 @@ const ( **AND** - `expression` 中的所有变量进行逻辑与操作。 +`expression` 中的所有变量进行逻辑与操作。 示例代码: @@ -359,19 +359,19 @@ const ( func main(){ ... h := server.Default() - + m, err := casbin.NewCasbinMiddleware("example/config/model.conf", "example/config/policy.csv", subjectFromSession) if err != nil { log.Fatal(err) } - + h.GET("/book", m.RequiresPermissions("book:read", casbin.WithLogic(casbin.AND)), // 通过 func(ctx context.Context, c *app.RequestContext) { c.String(200, "you read the book successfully") }, ) - + h.GET("/book", m.RequiresPermissions("book:read book:write", casbin.WithLogic(casbin.AND)), // 不通过 func(ctx context.Context, c *app.RequestContext) { @@ -394,19 +394,19 @@ func main(){ func main(){ ... h := server.Default() - + m, err := casbin.NewCasbinMiddleware("example/config/model.conf", "example/config/policy.csv", subjectFromSession) if err != nil { log.Fatal(err) } - + h.GET("/book", m.RequiresPermissions("book:read", casbin.WithLogic(casbin.OR)), // 通过 func(ctx context.Context, c *app.RequestContext) { c.String(200, "you read the book successfully") }, ) - + h.GET("/book", m.RequiresPermissions("book:read book:and", casbin.WithLogic(casbin.OR)), // 通过 func(ctx context.Context, c *app.RequestContext) { @@ -433,33 +433,33 @@ func main(){ func main(){ ... h := server.Default() - + m, err := casbin.NewCasbinMiddleware("example/config/model.conf", "example/config/policy.csv", subjectFromSession) if err != nil { log.Fatal(err) } - + h.GET("/book", m.RequiresPermissions("book:read", casbin.WithLogic(casbin.CUSTOM)), // 通过 func(ctx context.Context, c *app.RequestContext) { c.String(200, "you read the book successfully") }, ) - + h.GET("/book", m.RequiresPermissions("book:read && book:write", casbin.WithLogic(casbin.CUSTOM)), // 不通过 func(ctx context.Context, c *app.RequestContext) { c.String(200, "you read the book successfully") }, ) - + h.GET("/book", m.RequiresPermissions("book:read || book:write", casbin.WithLogic(casbin.CUSTOM)), // 通过 func(ctx context.Context, c *app.RequestContext) { c.String(200, "you read the book successfully") }, ) - + h.GET("/book", m.RequiresPermissions("!book:read", casbin.WithLogic(casbin.CUSTOM)), // 不通过 func(ctx context.Context, c *app.RequestContext) { @@ -486,12 +486,12 @@ func WithPermissionParser(pp PermissionParserFunc) Option func main(){ ... h := server.Default() - + m, err := casbin.NewCasbinMiddleware("example/config/model.conf", "example/config/policy.csv", subjectFromSession) if err != nil { log.Fatal(err) } - + h.GET("/book", m.RequiresPermissions("book-read", casbin.WithPermissionParser(func(str string) []string { @@ -522,12 +522,12 @@ func WithPermissionParserSeparator(sep string) Option func main(){ ... h := server.Default() - + m, err := casbin.NewCasbinMiddleware("example/config/model.conf", "example/config/policy.csv", subjectFromSession) if err != nil { log.Fatal(err) } - + h.GET("/book", m.RequiresPermissions("book-read", casbin.WithPermissionParserSeparator("-"), @@ -556,12 +556,12 @@ func WithUnauthorized(u app.HandlerFunc) Option func main(){ ... h := server.Default() - + m, err := casbin.NewCasbinMiddleware("example/config/model.conf", "example/config/policy.csv", subjectFromSession) if err != nil { log.Fatal(err) } - + h.GET("/book", m.RequiresPermissions("book:read", casbin.WithUnauthorized(func(c context.Context, ctx *app.RequestContext) { @@ -592,12 +592,12 @@ func WithForbidden(f app.HandlerFunc) Option func main(){ ... h := server.Default() - + m, err := casbin.NewCasbinMiddleware("example/config/model.conf", "example/config/policy.csv", subjectFromSession) if err != nil { log.Fatal(err) } - + h.GET("/book", m.RequiresPermissions("book:read", casbin.WithForbidden(func(c context.Context, ctx *app.RequestContext) { diff --git a/content/zh/docs/hertz/tutorials/basic-feature/middleware/cors.md b/content/zh/docs/hertz/tutorials/basic-feature/middleware/cors.md index ec11e78b93..9b737ac837 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/middleware/cors.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/middleware/cors.md @@ -4,7 +4,6 @@ date: 2022-05-21 weight: 1 keywords: ["跨源资源共享"] description: "hertz 提供 cors 跨域中间件的实现。" - --- 跨源资源共享(CORS)机制允许服务器标识除了它自己的其它 origin,使得浏览器可以访问加载这些资源; @@ -66,20 +65,20 @@ Hertz 通过使用 cors 中间件,为客户端提供了跨源资源访问的 上述**示例代码**中只配置了部分可选参数,`Config` 的完整参数列表如下: -| 参数 | 介绍 | -| ---------------------- |----------------------------------------------------------------| -| AllowAllOrigins | 用于设置允许来自任意 origin 的客户端访问服务端资源,默认为 `false` | -| AllowOrigins | 用于设置允许跨源访问的 origin 列表,默认为 `[]` | -| AllowOriginFunc | 用于设置校验客户端 origin 的函数,当启用这个配置时,`AllowOrigins` 的内容将被忽略 | -| AllowMethods | 用于设置允许客户端跨源访问所使用的 HTTP 方法列表(在接收到预检请求时生效) | -| AllowHeaders | 用于设置客户端发起**非简单**的跨源资源访问请求时,允许使用的头信息字段列表,默认为 `[]`(在接收到预检请求时生效) | -| AllowCredentials | 用于设置允许客户端请求携带用户凭证,如:cookies,token,SSL 凭证,默认为 `false` | -| ExposeHeaders | 用于设置允许暴露给客户端的响应头列表,默认为 `[]` | -| MaxAge | 用于设置预检请求的有效期(有效期内不会发起重复的预检请求) | -| AllowWildcard | 用于设置允许含通配符的 origin 访问资源,默认为 `false` | -| AllowBrowserExtensions | 用于设置允许使用流行的浏览器扩展模式,默认为 `false` | -| AllowWebSockets | 用于设置允许使用 WebSocket 协议,默认为 `false` | -| AllowFiles | 用于设置允许使用 `file://` 协议(危险)除非你能确保 100% 的安全,才可以使用它,默认为 `false` | +| 参数 | 介绍 | +| ---------------------- | ----------------------------------------------------------------------------------------------------------------- | +| AllowAllOrigins | 用于设置允许来自任意 origin 的客户端访问服务端资源,默认为 `false` | +| AllowOrigins | 用于设置允许跨源访问的 origin 列表,默认为 `[]` | +| AllowOriginFunc | 用于设置校验客户端 origin 的函数,当启用这个配置时,`AllowOrigins` 的内容将被忽略 | +| AllowMethods | 用于设置允许客户端跨源访问所使用的 HTTP 方法列表(在接收到预检请求时生效) | +| AllowHeaders | 用于设置客户端发起**非简单**的跨源资源访问请求时,允许使用的头信息字段列表,默认为 `[]`(在接收到预检请求时生效) | +| AllowCredentials | 用于设置允许客户端请求携带用户凭证,如:cookies,token,SSL 凭证,默认为 `false` | +| ExposeHeaders | 用于设置允许暴露给客户端的响应头列表,默认为 `[]` | +| MaxAge | 用于设置预检请求的有效期(有效期内不会发起重复的预检请求) | +| AllowWildcard | 用于设置允许含通配符的 origin 访问资源,默认为 `false` | +| AllowBrowserExtensions | 用于设置允许使用流行的浏览器扩展模式,默认为 `false` | +| AllowWebSockets | 用于设置允许使用 WebSocket 协议,默认为 `false` | +| AllowFiles | 用于设置允许使用 `file://` 协议(危险)除非你能确保 100% 的安全,才可以使用它,默认为 `false` | ### AllowAllOrigins diff --git a/content/zh/docs/hertz/tutorials/basic-feature/middleware/csrf.md b/content/zh/docs/hertz/tutorials/basic-feature/middleware/csrf.md index 216cb1152c..42e771267a 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/middleware/csrf.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/middleware/csrf.md @@ -12,7 +12,7 @@ Hertz 提供了 [CSRF](https://github.com/hertz-contrib/csrf) 中间件,可帮 ## 安装 -``` shell +```shell go get github.com/hertz-contrib/csrf ``` @@ -53,14 +53,14 @@ func main() { ## 配置 -| 配置项 | 默认值 | 介绍 | -| --------------- | ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | -| `Secret` | `csrfSecret` | 用于生成令牌(必要配置) | -| `IgnoreMethods` | "GET", "HEAD", "OPTIONS", "TRACE" | 被忽略的方法将将视为无需 `csrf` 保护 | -| `Next` | `nil` | `Next` 定义了一个函数,当返回真时,跳过这个 `csrf` 中间件。 | -| `KeyLookup` | `header:X-CSRF-TOKEN` | `KeyLookup` 是一个""形式的字符串,用于创建一个从请求中提取令牌的 Extractor。 | -| `ErrorFunc` | `func(ctx context.Context, c *app.RequestContext) { panic(c.Errors.Last()) }` | 当 `app.HandlerFunc` 返回一个错误时,`ErrorFunc` 被执行 | -| `Extractor` | 基于 KeyLookup 创建 | `Extractor` 返回`csrf token`。如果设置了这个,它将被用来代替基于 `KeyLookup` 的 `Extractor`。 | +| 配置项 | 默认值 | 介绍 | +| --------------- | ----------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | +| `Secret` | `csrfSecret` | 用于生成令牌(必要配置) | +| `IgnoreMethods` | "GET", "HEAD", "OPTIONS", "TRACE" | 被忽略的方法将将视为无需 `csrf` 保护 | +| `Next` | `nil` | `Next` 定义了一个函数,当返回真时,跳过这个 `csrf` 中间件。 | +| `KeyLookup` | `header:X-CSRF-TOKEN` | `KeyLookup` 是一个""形式的字符串,用于创建一个从请求中提取令牌的 Extractor。 | +| `ErrorFunc` | `func(ctx context.Context, c *app.RequestContext) { panic(c.Errors.Last()) }` | 当 `app.HandlerFunc` 返回一个错误时,`ErrorFunc` 被执行 | +| `Extractor` | 基于 KeyLookup 创建 | `Extractor` 返回`csrf token`。如果设置了这个,它将被用来代替基于 `KeyLookup` 的 `Extractor`。 | ### WithSecret @@ -115,7 +115,7 @@ func main() { 函数签名: ```go -func WithIgnoredMethods(methods []string) Option +func WithIgnoredMethods(methods []string) Option ``` 默认值:`{"GET", "HEAD", "OPTIONS", "TRACE"}` @@ -283,7 +283,7 @@ package main import ( "context" - + "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/hertz-contrib/csrf" @@ -347,7 +347,7 @@ package main import ( "context" "errors" - + "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/hertz-contrib/csrf" diff --git a/content/zh/docs/hertz/tutorials/basic-feature/middleware/etag.md b/content/zh/docs/hertz/tutorials/basic-feature/middleware/etag.md index 22d6abcc1c..7ae8858d11 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/middleware/etag.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/middleware/etag.md @@ -49,11 +49,11 @@ func main() { ## 配置 -| 配置 | 默认值 | 介绍 | -|-------------|-------|------------------------------------------| -| WithWeak | false | 使用弱验证器 | -| WithNext | nil | 定义一个 Next 函数,当返回值为 `true` 时跳过 `etag` 中间件 | -|WithGenerator | nil | 自定义 ETag 生成逻辑 | +| 配置 | 默认值 | 介绍 | +| ------------- | ------ | ---------------------------------------------------------- | +| WithWeak | false | 使用弱验证器 | +| WithNext | nil | 定义一个 Next 函数,当返回值为 `true` 时跳过 `etag` 中间件 | +| WithGenerator | nil | 自定义 ETag 生成逻辑 | ### WithWeak @@ -96,7 +96,7 @@ func main() { 函数签名: ```go -func WithNext(next NextFunc) Option +func WithNext(next NextFunc) Option ``` 示例代码: diff --git a/content/zh/docs/hertz/tutorials/basic-feature/middleware/gzip.md b/content/zh/docs/hertz/tutorials/basic-feature/middleware/gzip.md index 03eb6e8ddf..2af548d3c5 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/middleware/gzip.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/middleware/gzip.md @@ -1,11 +1,9 @@ --- - title: "Gzip 压缩" date: 2022-10-19 weight: 4 keywords: ["Gzip", "压缩"] description: "Hertz 提供了 Gzip 的实现。" - --- 在 HTTP 中,GNUzip(Gzip) 压缩编码是一种用来优化 Web 应用程序性能的方式,并且 Hertz 也提供了 Gzip 的 [实现](https://github.com/hertz-contrib/gzip) 。 diff --git a/content/zh/docs/hertz/tutorials/basic-feature/middleware/i18n.md b/content/zh/docs/hertz/tutorials/basic-feature/middleware/i18n.md index 11ca1793fc..9607dd424a 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/middleware/i18n.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/middleware/i18n.md @@ -4,7 +4,6 @@ date: 2022-09-01 weight: 5 keywords: ["国际化", "i18n"] description: "Hertz 提供了国际化 (i18n) 的中间件扩展。" - --- Hertz 提供了国际化 (i18n) 的 [中间件扩展](https://github.com/hertz-contrib/i18n) ,它参考了 Gin 的 [实现](https://github.com/gin-contrib/i18n) 。 @@ -189,14 +188,14 @@ func main() { **配置项** -| 配置项 | 类型 | 默认值 | 描述 | -| :--------------- | ------------------ | -------------------------------------------------------- | ---------------------------------------------- | -| DefaultLanguage | language.Tag | language.English | 默认转换语言类型 | -| FormatBundleFile | string | "yaml" | 转换文件模板类型,例如:yaml, json | +| 配置项 | 类型 | 默认值 | 描述 | +| :--------------- | ------------------ | ------------------------------------------------ | ---------------------------------------------- | +| DefaultLanguage | language.Tag | language.English | 默认转换语言类型 | +| FormatBundleFile | string | "yaml" | 转换文件模板类型,例如:yaml, json | | AcceptLanguage | []language.Tag | []language.Tag{defaultLanguage,language.Chinese} | 接收转换类型 | -| RootPath | string | defaultRootPath | 模板文件目录 | -| UnmarshalFunc | i18n.UnmarshalFunc | yaml.Unmarshal | 模板文件解码函数,例如:yaml.Unmarshal | -| Loader | Loader | LoaderFunc(ioutil.ReadFile) | 文件读取函数,例如 LoaderFunc(ioutil.ReadFile) | +| RootPath | string | defaultRootPath | 模板文件目录 | +| UnmarshalFunc | i18n.UnmarshalFunc | yaml.Unmarshal | 模板文件解码函数,例如:yaml.Unmarshal | +| Loader | Loader | LoaderFunc(ioutil.ReadFile) | 文件读取函数,例如 LoaderFunc(ioutil.ReadFile) | ### WithGetLangHandle diff --git a/content/zh/docs/hertz/tutorials/basic-feature/middleware/jwt.md b/content/zh/docs/hertz/tutorials/basic-feature/middleware/jwt.md index b6f256501c..5e40a92f78 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/middleware/jwt.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/middleware/jwt.md @@ -4,7 +4,6 @@ date: 2022-06-09 weight: 3 keywords: ["JWT 认证", "JSON Web Token", "JWT"] description: "Hertz 提供了 jwt 的实现。" - --- JSON Web Token(JWT)是一个轻量级的认证规范,这个规范允许我们使用 JWT 在用户和服务器之间传递安全可靠的信息。其本质是一个 token,是一种紧凑的 URL 安全方法,用于在网络通信的双方之间传递。 @@ -154,38 +153,38 @@ Hertz 通过使用中间件,为路由请求提供了 `jwt` 的校验功能。 上述**示例代码**中,只传入了**两项必要的**自定义的配置。关于 `HertzJWTMiddleware` 的更多常用配置如下: -| 参数 | 介绍 | -|:------------------------------|:---------------------------------------------------------------------------------------| -| `Realm` | 用于设置所属领域名称,默认为 `hertz jwt` | -| `SigningAlgorithm` | 用于设置签名算法,可以是 HS256、HS384、HS512、RS256、RS384 或者 RS512 等,默认为 `HS256` | -| `Key` | 用于设置签名密钥(必要配置) | -| `KeyFunc` | 用于设置获取签名密钥的回调函数,设置后 token 解析时将从 `KeyFunc` 获取 `jwt` 签名密钥 | -| `Timeout` | 用于设置 token 过期时间,默认为一小时 | +| 参数 | 介绍 | +| :---------------------------- | :---------------------------------------------------------------------------------------------------------------------- | +| `Realm` | 用于设置所属领域名称,默认为 `hertz jwt` | +| `SigningAlgorithm` | 用于设置签名算法,可以是 HS256、HS384、HS512、RS256、RS384 或者 RS512 等,默认为 `HS256` | +| `Key` | 用于设置签名密钥(必要配置) | +| `KeyFunc` | 用于设置获取签名密钥的回调函数,设置后 token 解析时将从 `KeyFunc` 获取 `jwt` 签名密钥 | +| `Timeout` | 用于设置 token 过期时间,默认为一小时 | | `MaxRefresh` | 用于设置最大 token 刷新时间,允许客户端在 `TokenTime` + `MaxRefresh` 内刷新 token 的有效时间,追加一个 `Timeout` 的时长 | -| `Authenticator` | 用于设置登录时认证用户信息的函数(必要配置) | -| `Authorizator` | 用于设置授权已认证的用户路由访问权限的函数 | -| `PayloadFunc` | 用于设置登陆成功后为向 token 中添加自定义负载信息的函数 | -| `Unauthorized` | 用于设置 jwt 验证流程失败的响应函数 | -| `LoginResponse` | 用于设置登录的响应函数 | -| `LogoutResponse` | 用于设置登出的响应函数 | -| `RefreshResponse` | 用于设置 token 有效时长刷新后的响应函数 | -| `IdentityHandler` | 用于设置获取身份信息的函数,默认与 `IdentityKey` 配合使用 | -| `IdentityKey` | 用于设置检索身份的键,默认为 `identity` | -| `TokenLookup` | 用于设置 token 的获取源,可以选择 `header`、`query`、`cookie`、`param`、`form`,默认为 `header:Authorization` | -| `TokenHeadName` | 用于设置从 header 中获取 token 时的前缀,默认为 `Bearer` | -| `WithoutDefaultTokenHeadName` | 用于设置 `TokenHeadName` 为空,默认为 `false` | -| `TimeFunc` | 用于设置获取当前时间的函数,默认为 `time.Now()` | -| `HTTPStatusMessageFunc` | 用于设置 jwt 校验流程发生错误时响应所包含的错误信息 | +| `Authenticator` | 用于设置登录时认证用户信息的函数(必要配置) | +| `Authorizator` | 用于设置授权已认证的用户路由访问权限的函数 | +| `PayloadFunc` | 用于设置登陆成功后为向 token 中添加自定义负载信息的函数 | +| `Unauthorized` | 用于设置 jwt 验证流程失败的响应函数 | +| `LoginResponse` | 用于设置登录的响应函数 | +| `LogoutResponse` | 用于设置登出的响应函数 | +| `RefreshResponse` | 用于设置 token 有效时长刷新后的响应函数 | +| `IdentityHandler` | 用于设置获取身份信息的函数,默认与 `IdentityKey` 配合使用 | +| `IdentityKey` | 用于设置检索身份的键,默认为 `identity` | +| `TokenLookup` | 用于设置 token 的获取源,可以选择 `header`、`query`、`cookie`、`param`、`form`,默认为 `header:Authorization` | +| `TokenHeadName` | 用于设置从 header 中获取 token 时的前缀,默认为 `Bearer` | +| `WithoutDefaultTokenHeadName` | 用于设置 `TokenHeadName` 为空,默认为 `false` | +| `TimeFunc` | 用于设置获取当前时间的函数,默认为 `time.Now()` | +| `HTTPStatusMessageFunc` | 用于设置 jwt 校验流程发生错误时响应所包含的错误信息 | | `SendCookie` | 用于设置 token 将同时以 cookie 的形式返回,下列 cookie 相关配置生效的前提是该值为 `true`,默认为 `false` | -| `CookieMaxAge` | 用于设置 cookie 的有效期,默认为 `Timeout` 定义的一小时 | -| `SecureCookie` | 用于设置允许不通过 HTTPS 传递 cookie 信息,默认为 `false` | -| `CookieHTTPOnly` | 用于设置允许客户端访问 cookie 以进行开发,默认为 `false` | -| `CookieDomain` | 用于设置 cookie 所属的域,默认为空 | -| `SendAuthorization` | 用于设置为所有请求的响应头添加授权的 token 信息,默认为 `false` | -| `DisabledAbort` | 用于设置在 jwt 验证流程出错时,禁止请求上下文调用 `abort()`,默认为 `false` | -| `CookieName` | 用于设置 cookie 的 name 值 | -| `CookieSameSite` | 用于设置使用 `protocol.CookieSameSite` 声明的参数设置 cookie 的 SameSite 属性值 | - | `ParseOptions` | 用于设置使用 `jwt.ParserOption` 声明的函数选项式参数配置 `jwt.Parser` 的属性值 | +| `CookieMaxAge` | 用于设置 cookie 的有效期,默认为 `Timeout` 定义的一小时 | +| `SecureCookie` | 用于设置允许不通过 HTTPS 传递 cookie 信息,默认为 `false` | +| `CookieHTTPOnly` | 用于设置允许客户端访问 cookie 以进行开发,默认为 `false` | +| `CookieDomain` | 用于设置 cookie 所属的域,默认为空 | +| `SendAuthorization` | 用于设置为所有请求的响应头添加授权的 token 信息,默认为 `false` | +| `DisabledAbort` | 用于设置在 jwt 验证流程出错时,禁止请求上下文调用 `abort()`,默认为 `false` | +| `CookieName` | 用于设置 cookie 的 name 值 | +| `CookieSameSite` | 用于设置使用 `protocol.CookieSameSite` 声明的参数设置 cookie 的 SameSite 属性值 | +| `ParseOptions` | 用于设置使用 `jwt.ParserOption` 声明的函数选项式参数配置 `jwt.Parser` 的属性值 | ### Key diff --git a/content/zh/docs/hertz/tutorials/basic-feature/middleware/keyauth.md b/content/zh/docs/hertz/tutorials/basic-feature/middleware/keyauth.md index 4d3f741d83..1057aa4dc6 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/middleware/keyauth.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/middleware/keyauth.md @@ -4,7 +4,6 @@ date: 2022-09-22 weight: 7 keywords: ["KeyAuth", "token 鉴权"] description: "Hertz 提供了 keyauth 扩展用于帮助用户实现 `token` 鉴权。" - --- Hertz 提供了 [keyauth](https://github.com/hertz-contrib/keyauth) 扩展用于帮助用户实现 `token` 鉴权。 [keyauth](https://github.com/hertz-contrib/keyauth) 扩展的实现参考了 [Fiber](https://github.com/gofiber/fiber) 和 [Echo](https://github.com/labstack/echo) 的实现。 diff --git a/content/zh/docs/hertz/tutorials/basic-feature/middleware/paseto.md b/content/zh/docs/hertz/tutorials/basic-feature/middleware/paseto.md index 1615a21d2f..c8c1dce56c 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/middleware/paseto.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/middleware/paseto.md @@ -80,14 +80,14 @@ func main() { ## 配置项 -| 配置 | 默认值 | 介绍 | -|----------------|----------------------------------------------------------------------------------------------|-------------------------------------------------| -| Next | [nil](https://github.com/hertz-contrib/paseto/blob/main/option.go#L88) | 用于设置一个函数,当返回 true 时跳过这个中间件 | -| ErrorFunc | [输出日志并返回 401](https://github.com/hertz-contrib/paseto/blob/main/option.go#L89) | 用于设置一个在发生错误时执行的函数 | -| SuccessHandler | [将声明保存到 app.RequestContext](https://github.com/hertz-contrib/paseto/blob/main/option.go#L94) | 用于设置一个函数,该函数在令牌有效时执行 | -| KeyLookup | [header:Authorization](https://github.com/hertz-contrib/paseto/blob/main/option.go#L97) | 用于设置一个“<source>:<key>”形式的字符串,用于创建从请求中提取令牌的提取器 | -| TokenPrefix | "" | 用于设置一个字符串,用于保存令牌查找的前缀 | -| ParseFunc | [解析 V4 公共令牌](https://github.com/hertz-contrib/paseto/blob/main/option.go#L98) | 用于设置一个解析并验证令牌的函数 | +| 配置 | 默认值 | 介绍 | +| -------------- | -------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | +| Next | [nil](https://github.com/hertz-contrib/paseto/blob/main/option.go#L88) | 用于设置一个函数,当返回 true 时跳过这个中间件 | +| ErrorFunc | [输出日志并返回 401](https://github.com/hertz-contrib/paseto/blob/main/option.go#L89) | 用于设置一个在发生错误时执行的函数 | +| SuccessHandler | [将声明保存到 app.RequestContext](https://github.com/hertz-contrib/paseto/blob/main/option.go#L94) | 用于设置一个函数,该函数在令牌有效时执行 | +| KeyLookup | [header:Authorization](https://github.com/hertz-contrib/paseto/blob/main/option.go#L97) | 用于设置一个“<source>:<key>”形式的字符串,用于创建从请求中提取令牌的提取器 | +| TokenPrefix | "" | 用于设置一个字符串,用于保存令牌查找的前缀 | +| ParseFunc | [解析 V4 公共令牌](https://github.com/hertz-contrib/paseto/blob/main/option.go#L98) | 用于设置一个解析并验证令牌的函数 | ### Next @@ -234,12 +234,12 @@ func performRequest() { func main() { h := server.New(server.WithHostPorts(":8080")) - + handler := func(ctx context.Context, c *app.RequestContext) { c.JSON(http.StatusUnauthorized, "invalid token") c.Abort() } - + h.GET("/paseto/withsecret", func(c context.Context, ctx *app.RequestContext) { now := time.Now() genTokenFunc := paseto.DefaultGenTokenFunc() @@ -622,12 +622,12 @@ func main() { ## 版本比较 -| 版本 | 本地 | 公共 | -|-----|--------------------------------------------------|------------------------| -| v1 | 使用“AES-256-CBC”加密并使用 HMAC-SHA-256 签名 | 使用 `RSA-SHA-256` 签名 | -| v2 | 使用“XSalsa20Poly-1305”加密并使用“HMAC-SHA-384”签名` | 使用 `EdDSA`(`Ed25519`)签名 | | -| v3 | 使用“XChaCha20Poly1305”加密并使用“HMAC-SHA-384”签名` | 使用 `EdDSA`(`Ed25519`)签名 | | -| v4 | 使用“XChaCha20Poly1305”加密,并使用“HMAC-SHA-512-256”签名` | 使用 `EdDSA`(`Ed448`)签名 | | +| 版本 | 本地 | 公共 | +| ---- | ---------------------------------------------------------- | ----------------------------- | --- | +| v1 | 使用“AES-256-CBC”加密并使用 HMAC-SHA-256 签名 | 使用 `RSA-SHA-256` 签名 | +| v2 | 使用“XSalsa20Poly-1305”加密并使用“HMAC-SHA-384”签名` | 使用 `EdDSA`(`Ed25519`)签名 | | +| v3 | 使用“XChaCha20Poly1305”加密并使用“HMAC-SHA-384”签名` | 使用 `EdDSA`(`Ed25519`)签名 | | +| v4 | 使用“XChaCha20Poly1305”加密,并使用“HMAC-SHA-512-256”签名` | 使用 `EdDSA`(`Ed448`)签名 | | ## 完整示例 diff --git a/content/zh/docs/hertz/tutorials/basic-feature/middleware/pprof.md b/content/zh/docs/hertz/tutorials/basic-feature/middleware/pprof.md index 44f203af9c..8666a5e8de 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/middleware/pprof.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/middleware/pprof.md @@ -4,10 +4,8 @@ date: 2022-09-24 weight: 7 keywords: ["pprof", "性能分析"] description: "Hertz 提供了 pprof 扩展,帮助用户对 Hertz 项目进行性能分析。" - --- - Hertz 提供了 [pprof](https://github.com/hertz-contrib/pprof) 扩展,帮助用户对 Hertz 项目进行性能分析,[pprof](https://github.com/hertz-contrib/pprof) 扩展的实现参考了 [Gin](https://github.com/gin-contrib/pprof) 的实现。 ## 安装 @@ -99,8 +97,8 @@ RouteRegister(rg *route.RouterGroup, prefixOptions ...string) 本方式注册后的 `pprof` 前缀为路由组的前缀与自定义前缀拼接后的结果。 -* 用户不指定前缀,注册后的 `pprof` 的前缀为路由组的前缀与默认前缀 `/debug/pprof` 拼接后的结果,即为 `/xxx/debug/pprof`(`xxx` 为路由组前缀); -* 用户指定前缀,注册后的 `pprof` 的前缀为路由组的的前缀与自定义前缀拼接后的结果,比如下文示例中注册后的 `pprof` 前缀为 `/admin/pprof`。 +- 用户不指定前缀,注册后的 `pprof` 的前缀为路由组的前缀与默认前缀 `/debug/pprof` 拼接后的结果,即为 `/xxx/debug/pprof`(`xxx` 为路由组前缀); +- 用户指定前缀,注册后的 `pprof` 的前缀为路由组的的前缀与自定义前缀拼接后的结果,比如下文示例中注册后的 `pprof` 前缀为 `/admin/pprof`。 示例代码: @@ -140,9 +138,9 @@ func main() { 通过浏览器访问 `localhost:8888/debug/pprof` -* Hertz 端口号默认为 8888 -* pprof 默认地址前缀为 `debug/pprof` -* 端口号和访问路由与用户实际端口号和 `pprof` 前缀一致 +- Hertz 端口号默认为 8888 +- pprof 默认地址前缀为 `debug/pprof` +- 端口号和访问路由与用户实际端口号和 `pprof` 前缀一致 ### 通过 `go tool pprof` 查看 diff --git a/content/zh/docs/hertz/tutorials/basic-feature/middleware/recovery.md b/content/zh/docs/hertz/tutorials/basic-feature/middleware/recovery.md index 3bd15ab62d..a25bd0da6d 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/middleware/recovery.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/middleware/recovery.md @@ -4,7 +4,6 @@ date: 2022-12-15 weight: 2 keywords: ["Recovery", "panic 恢复"] description: "Recovery 中间件是 Hertz 框架预置的中间件,为 Hertz 框架提供 panic 恢复的功能。" - --- Recovery 中间件是 Hertz 框架预置的中间件,使用 `server.Default()` 可以默认注册该中间件,为 Hertz 框架提供 panic 恢复的功能。 diff --git a/content/zh/docs/hertz/tutorials/basic-feature/middleware/requestid.md b/content/zh/docs/hertz/tutorials/basic-feature/middleware/requestid.md index eb92faac96..c2a1346d64 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/middleware/requestid.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/middleware/requestid.md @@ -4,7 +4,6 @@ date: 2022-10-01 weight: 9 keywords: ["Request ID", "X-Request-ID"] description: "Hertz 提供了可以对 `X-Request-ID` 进行操作的 Request ID 中间件。" - --- `X-Request-ID` 在 HTTP Headers 中是一种非标准响应字段,通常用于关联客户端和服务器之间的 HTTP 请求。 @@ -69,11 +68,11 @@ func main() { Hertz 通过使用中间件,可以在响应头中添加一个键为 `X-Request-ID` 的标识符,如果在请求头中设置了 `X-Request-ID` 字段,则会在响应头中将 `X-Request-ID` 原样返回。 Request ID 中间件提供了默认配置,用户也可以依据业务场景使用 `WithGenerator`,`WithCustomHeaderStrKey`,`WithHandler` 函数对以下配置项进行定制。 -| 配置 | 介绍 | -|------------------------|--------------------------------------| -| WithGenerator | 定义生成 Request ID 的函数,默认生成 UUID 标识符 | -| WithCustomHeaderStrKey | 定义 Request ID 的键值,默认为 `X-Request-ID` | -| WithHandler | 定义 Request ID 的处理函数 | +| 配置 | 介绍 | +| ---------------------- | ------------------------------------------------ | +| WithGenerator | 定义生成 Request ID 的函数,默认生成 UUID 标识符 | +| WithCustomHeaderStrKey | 定义 Request ID 的键值,默认为 `X-Request-ID` | +| WithHandler | 定义 Request ID 的处理函数 | ### 初始化 Request ID diff --git a/content/zh/docs/hertz/tutorials/basic-feature/middleware/secure.md b/content/zh/docs/hertz/tutorials/basic-feature/middleware/secure.md index 74b178c893..91f5418109 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/middleware/secure.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/middleware/secure.md @@ -59,16 +59,16 @@ Secure 所提供的配置项是为了简化一些常见的 HTTP headers 的配 Secure 提供 `New()` 函数用于将 Secure 集成进入 Hertz。默认配置如下所示 -| 配置函数 | 描述 | 默认值 | -|---------------------------|--------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------| -| WithSSLRedirect | `WithSSLRedirect` 设置为 true, 则将只允许 https 请求访问 | true | -| WithIsDevelopment | 如果 `WithIsDevelopment` 设置为 true, 则中间件应用的整个安全策略将被完全禁用 | false | -| WithSTSSecond | `WithSTSSecond` 用于设置 Strict-Transport-Security 的 max-age 的秒数 (second) | 315360000 | -| WithFrameDeny | `WithFrameDeny` 用于设置 X-Frame-Options 中的值,为 true 则设置值为 DENY | true | -| WithContentTypeNosniff | 如果 `WithContentTypeNosniff` 设置为 true,
则在 X-Content-Type-Options 中 添加 `nosniff` 值 | true | -| WithBrowserXssFilter | 如果 `WithBrowserXssFilter` 设置为 true,
则添加在 X-XSS-Protection 头中添加 `1; mode=block` 的值 | true | -| WithContentSecurityPolicy | `WithContentSecurityPolicy`
用于配置 Content-Security-Policy 中的策略 | "default-src 'self'" | -| WithIENoOpen | `WithIENoOpen` 用于防止 Internet Explorer 在网站的中执行下载任务,默认设置为 true, 即阻止下载 | true | +| 配置函数 | 描述 | 默认值 | +| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | +| WithSSLRedirect | `WithSSLRedirect` 设置为 true, 则将只允许 https 请求访问 | true | +| WithIsDevelopment | 如果 `WithIsDevelopment` 设置为 true, 则中间件应用的整个安全策略将被完全禁用 | false | +| WithSTSSecond | `WithSTSSecond` 用于设置 Strict-Transport-Security 的 max-age 的秒数 (second) | 315360000 | +| WithFrameDeny | `WithFrameDeny` 用于设置 X-Frame-Options 中的值,为 true 则设置值为 DENY | true | +| WithContentTypeNosniff | 如果 `WithContentTypeNosniff` 设置为 true,
则在 X-Content-Type-Options 中 添加 `nosniff` 值 | true | +| WithBrowserXssFilter | 如果 `WithBrowserXssFilter` 设置为 true,
则添加在 X-XSS-Protection 头中添加 `1; mode=block` 的值 | true | +| WithContentSecurityPolicy | `WithContentSecurityPolicy`
用于配置 Content-Security-Policy 中的策略 | "default-src 'self'" | +| WithIENoOpen | `WithIENoOpen` 用于防止 Internet Explorer 在网站的中执行下载任务,默认设置为 true, 即阻止下载 | true | | WIthSSLProxyHeaders | `WIthSSLProxyHeaders` 用于设置 **request headers map**。若请求是不安全的,就将请求头的信息和 **request headers map** 中的信息进行匹配。如果匹配到了相应的值,就把该请求视为安全的请求 | map[string]string{"X-Forwarded-Proto": "https"} | 当然,除了这些默认的配置项,我们还有其他的配置项在后续介绍 @@ -154,7 +154,7 @@ package main import ( "context" "net/http" - + "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/cloudwego/hertz/pkg/common/utils" diff --git a/content/zh/docs/hertz/tutorials/basic-feature/middleware/sentry.md b/content/zh/docs/hertz/tutorials/basic-feature/middleware/sentry.md index 3378e82246..e44a191b6b 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/middleware/sentry.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/middleware/sentry.md @@ -4,7 +4,6 @@ date: 2022-11-25 weight: 11 keywords: ["Sentry", "实时错误监控"] description: "Hertz 通过使用中间件 hertzsentry,整合了 Sentry-Go 的 SDK。" - --- Sentry 是一个开源的实时错误监控项目,支持很多平台,包括 Web 前端、服务器端、移动端和游戏端等。Hertz 通过使用中间件 [hertzsentry](https://github.com/hertz-contrib/hertzsentry) ,整合了 [Sentry-Go](https://docs.sentry.io/platforms/go/) 的 SDK。提供了一些统一的接口,帮助用户获得 sentry hub 和报告错误信息。 @@ -58,7 +57,7 @@ func main() { } // use sentry middleware and config with your requirements. - // attention! you should use sentry handler after recovery.Recovery() + // attention! you should use sentry handler after recovery.Recovery() h.Use(hertzsentry.NewSentry( hertzsentry.WithSendRequest(true), hertzsentry.WithRePanic(true), @@ -84,13 +83,13 @@ func main() { Hertz 通过使用中间件,整合了 Sentry-Go 的功能。其中 `hertzsentry.options` 结构定义了 hertzsentry 的配置信息,并提供了默认配置,用户也可以依据业务场景进行定制。 -| 参数 | 介绍 | -| --------------- | ------------------------------------------------------------ | -| rePanic | 用于配置 Sentry 在恢复后是否要再次 panic。如果使用了 Recover 中间件,则设置为 true,默认为 false。 | +| 参数 | 介绍 | +| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| rePanic | 用于配置 Sentry 在恢复后是否要再次 panic。如果使用了 Recover 中间件,则设置为 true,默认为 false。 | | waitForDelivery | 用于配置是否要在继续处理响应之前阻止请求并清空缓存区(**只有异步传输时才真正意义上有清空缓存区的操作**)。如果使用 Recover 中间件,跳过这个选项或将其设置为 false 是安全的,默认为 false。 | -| sendRequest | 用于配置在捕获 sentry 事件时是否要添加当前的请求头信息,默认为 false。 | -| sendBody | 用于配置在捕获 sentry 事件时是否要添加当前的请求正文信息,默认为 false。 | -| timeout | 用于配置 sentry 事件传递请求的超时时长,默认为 2 秒。 | +| sendRequest | 用于配置在捕获 sentry 事件时是否要添加当前的请求头信息,默认为 false。 | +| sendBody | 用于配置在捕获 sentry 事件时是否要添加当前的请求正文信息,默认为 false。 | +| timeout | 用于配置 sentry 事件传递请求的超时时长,默认为 2 秒。 | ### Flush(Go-Sentry) diff --git a/content/zh/docs/hertz/tutorials/basic-feature/middleware/session.md b/content/zh/docs/hertz/tutorials/basic-feature/middleware/session.md index a88c87f8b3..0f4d4141f5 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/middleware/session.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/middleware/session.md @@ -4,7 +4,6 @@ date: 2022-10-07 weight: 6 keywords: ["Session"] description: "Hertz 提供了 Session 的实现。" - --- Session 是服务器为了保存用户状态而创建的一种特殊的对象。 @@ -66,17 +65,17 @@ Hertz 通过使用中间件,可以对 Session 进行一系列的操作配置 **注意:** Session 接口对 [gorilla-session](https://github.com/gorilla/sessions) 的方法进行了简单封装。 -| 方法 | 函数签名 | 介绍 | -|----------|-----------------------------------------------|----------------------------------------| +| 方法 | 函数签名 | 介绍 | +| -------- | --------------------------------------------- | ------------------------------------------------------------------- | | ID | `ID() string` | 用于获取存储时生成的 Session ID,它不应该作为用户信息的一部分去使用 | -| Get | `Get(key interface{}) interface{}` | 用于根据给定的键值参数获取 Session 值 | -| Set | `Set(key, val interface{})` | 用于设置与给定键值相关联的 Session 值 | -| Delete | `Delete(key interface{})` | 用于根据给定的键值删除相关联的 Session 值 | -| Clear | `Clear()` | 用于删除 Session 中存储的所有值 | -| AddFlash | `AddFlash(value interface{}, vars ...string)` | 用于向 Session 添加一条 flash message | -| Flashes | `Flashes(vars ...string) []interface{}` | 用于获取 Session 中的 flash message | -| Options | `Options(Options)` | 用于设置 Session 的配置 | -| Save | `Save() error` | 用于保存当前请求期间使用的所有会话 | +| Get | `Get(key interface{}) interface{}` | 用于根据给定的键值参数获取 Session 值 | +| Set | `Set(key, val interface{})` | 用于设置与给定键值相关联的 Session 值 | +| Delete | `Delete(key interface{})` | 用于根据给定的键值删除相关联的 Session 值 | +| Clear | `Clear()` | 用于删除 Session 中存储的所有值 | +| AddFlash | `AddFlash(value interface{}, vars ...string)` | 用于向 Session 添加一条 flash message | +| Flashes | `Flashes(vars ...string) []interface{}` | 用于获取 Session 中的 flash message | +| Options | `Options(Options)` | 用于设置 Session 的配置 | +| Save | `Save() error` | 用于保存当前请求期间使用的所有会话 | ### NewStore diff --git a/content/zh/docs/hertz/tutorials/basic-feature/middleware/swagger.md b/content/zh/docs/hertz/tutorials/basic-feature/middleware/swagger.md index 045df0ed0f..83eec15e2c 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/middleware/swagger.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/middleware/swagger.md @@ -4,7 +4,6 @@ date: 2022-10-06 weight: 8 keywords: ["Swagger", "RESTful API"] description: "用 Swagger 2.0 来自动生成 RESTful API 文档的 Hertz 中间件。" - --- 这是一个用 Swagger 2.0 来自动生成 RESTful API 文档的 Hertz 中间件。 @@ -42,11 +41,11 @@ swag init swag init --parseDependency --parseInternal --parseDepth 5 --instanceName "swagger" ``` -| 选项 | 默认值 | 描述 | -| --------------- |-----------|---------------------------------------------------------------------| -| parseInternal | false | 解析内部依赖包。 | -| parseDependency | false | 解析外部依赖包。 | -| parseDepth | 100 | 解析依赖包深度,如果你知道解析结构的深度,推荐使用这个参数,swag 命令的执行时间会显著减少。 | +| 选项 | 默认值 | 描述 | +| --------------- | --------- | -------------------------------------------------------------------------------------------------------------- | +| parseInternal | false | 解析内部依赖包。 | +| parseDependency | false | 解析外部依赖包。 | +| parseDepth | 100 | 解析依赖包深度,如果你知道解析结构的深度,推荐使用这个参数,swag 命令的执行时间会显著减少。 | | instanceName | "swagger" | swagger 文档的实例名称。如果要在一个 Hertz 路由上部署多个不同的 swagger 实例,请确保每个实例有一个唯一的名字。 | 4. 通过运行以下命令在工程中下载 [hertz-swagger](https://github.com/hertz-contrib/swagger) : @@ -195,13 +194,13 @@ func main() { ``` -| 选项 | 类型 | 默认值 | 描述 | -| ------------------------ | ------ | ---------- | ------------------------------------------------------------ | -| URL | string | "doc.json" | 指向 API 定义的 URL | +| 选项 | 类型 | 默认值 | 描述 | +| ------------------------ | ------ | ---------- | ---------------------------------------------------------------------------------------------------------- | +| URL | string | "doc.json" | 指向 API 定义的 URL | | DocExpansion | string | "list" | 控制操作和标签的默认扩展设置。它可以是 `list`(只展开标签)、`full`(展开标签和操作)或 `none`(不展开)。 | -| DeepLinking | bool | true | 如果设置为 `true`,可以启用标签和操作的深度链接。更多信息请参见深度链接文档。 | -| DefaultModelsExpandDepth | int | 1 | 模型的默认扩展深度(设置为 -1 完全隐藏模型)。 | -| PersistAuthorization | bool | false | 如果设置为 `true`,则会持久化保存授权数据,在浏览器关闭/刷新时不会丢失。 | -| Oauth2DefaultClientID | string | "" | 如果设置了这个字段,它将用于预填 OAuth2 授权对话框的 *client_id* 字段。 | +| DeepLinking | bool | true | 如果设置为 `true`,可以启用标签和操作的深度链接。更多信息请参见深度链接文档。 | +| DefaultModelsExpandDepth | int | 1 | 模型的默认扩展深度(设置为 -1 完全隐藏模型)。 | +| PersistAuthorization | bool | false | 如果设置为 `true`,则会持久化保存授权数据,在浏览器关闭/刷新时不会丢失。 | +| Oauth2DefaultClientID | string | "" | 如果设置了这个字段,它将用于预填 OAuth2 授权对话框的 _client_id_ 字段。 | [Swag]: https://github.com/swaggo/swag diff --git a/content/zh/docs/hertz/tutorials/basic-feature/network-lib.md b/content/zh/docs/hertz/tutorials/basic-feature/network-lib.md index 830ff4aa21..0d74a5a23b 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/network-lib.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/network-lib.md @@ -4,14 +4,13 @@ date: 2022-05-20 weight: 4 keywords: ["netpoll", "go net"] description: "Hertz 默认集成了 Netpoll 和 Golang 原生网络库两个网络库,用户可以根据自己的场景选择合适的网络库以达到最佳性能。" - --- ## 使用方式 对于 Server 来说,默认使用 netpoll,可以通过配置项进行更改: ->注意:netpoll 目前不支持 Windows,Windows 会通过条件编译将网络库自动切换为 go net。 +> 注意:netpoll 目前不支持 Windows,Windows 会通过条件编译将网络库自动切换为 go net。 ```go server.New(server.WithTransport(standard.NewTransporter)) @@ -29,8 +28,8 @@ client.NewClient(client.WithDialer(netpoll.NewDialer())) 1. 如果有启动 TLS Server 的需求,请使用 `go net` 网络库。`netpoll` 正在实现对 TLS 的支持。 2. 由于网络库触发模式的不同:`go net` 为 ET 模型,`netpoll` 为 LT 模型,使得两个网络库的适用场景有一些不同。 -在 ET 模型下,由框架处理 Read / Write 事件;在 LT 模型下,由网络库处理 Read / Write 事件。 -使得在小包场景下,由于更优的调度策略使得 LT 性能更好;在大包场景下,由于读 / 写不受框架层控制,使得大量数据被读入内存而不能及时处理,可能会造成内存压力。 + 在 ET 模型下,由框架处理 Read / Write 事件;在 LT 模型下,由网络库处理 Read / Write 事件。 + 使得在小包场景下,由于更优的调度策略使得 LT 性能更好;在大包场景下,由于读 / 写不受框架层控制,使得大量数据被读入内存而不能及时处理,可能会造成内存压力。 - 在较大 request size 下(request size > 1M),推荐使用 go net 网络库加流式。 - 在其他场景下,推荐使用 netpoll 网络库,会获得极致的性能。 diff --git a/content/zh/docs/hertz/tutorials/basic-feature/protocol/_index.md b/content/zh/docs/hertz/tutorials/basic-feature/protocol/_index.md index 4a9de96bf8..870eaf373b 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/protocol/_index.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/protocol/_index.md @@ -4,7 +4,6 @@ date: 2022-05-23 weight: 7 keywords: ["TLS", "ALPN", "Websocket", "HTTP2", "HTTP3", "SSE"] description: "Hertz 支持的协议。" - --- ## TLS @@ -24,10 +23,10 @@ Hertz 基于 `hijack` 的方式实现了对 WebSocket 的支持。 Hertz 参考 [net/http2](https://github.com/golang/net/tree/master/http2) 实现了对 HTTP2 的支持,同时支持 h2 和 h2c。 -## HTTP3 +## HTTP3 Hertz 参考 [quic-go](https://github.com/quic-go/quic-go) 实现了对 HTTP3 的支持。 ## SSE -Hertz 支持 SSE,允许服务器端通过简单的 HTTP 响应向客户端发送事件。 \ No newline at end of file +Hertz 支持 SSE,允许服务器端通过简单的 HTTP 响应向客户端发送事件。 diff --git a/content/zh/docs/hertz/tutorials/basic-feature/protocol/http2.md b/content/zh/docs/hertz/tutorials/basic-feature/protocol/http2.md index ba7bd5d64e..bb71a16272 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/protocol/http2.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/protocol/http2.md @@ -189,7 +189,7 @@ func main() { | 配置 | 默认值 | 介绍 | | :----------------- | :------ | -------------------------------------------- | | `ReadTimeout` | `0` | 建立连接后,从服务器读取到可用资源的超时时间 | -| `DisableKeepAlive` | `false` | 是否关闭 `Keep-Alive` 模式 | +| `DisableKeepAlive` | `false` | 是否关闭 `Keep-Alive` 模式 | 示例代码: @@ -311,20 +311,20 @@ func WithDisableKeepAlive(disableKeepAlive bool) Option ### 客户端 -| 配置 | 默认值 | 介绍 | -| ---------------------------- | ----------------------------- | ------------------------------------------------------------------ | -| `MaxHeaderListSize` | `0`,指使用默认的限制(10MB) | 指 http2 规范中的 `SETTINGS_MAX_HEADER_LIST_SIZE`。 | -| `AllowHTTP` | `false` | 设置是否允许 http,h2c 模式的开关 | +| 配置 | 默认值 | 介绍 | +| ---------------------------- | ----------------------------- | -------------------------------------------------------------------- | +| `MaxHeaderListSize` | `0`,指使用默认的限制(10MB) | 指 http2 规范中的 `SETTINGS_MAX_HEADER_LIST_SIZE`。 | +| `AllowHTTP` | `false` | 设置是否允许 http,h2c 模式的开关 | | `ReadIdleTimeout` | `0`,即不进行健康检查 | 若连接在该段时间间隔内未接收到任何帧,将使用 `ping` 帧进行健康检查。 | -| `PingTimeout` | `15s` | 超时时间,如果未收到对 `Ping` 的响应,连接将在该超时时间后关闭。 | -| `WriteByteTimeout` | `0` | 若在该段时间间隔内未写入任何数据,将关闭连接。 | +| `PingTimeout` | `15s` | 超时时间,如果未收到对 `Ping` 的响应,连接将在该超时时间后关闭。 | +| `WriteByteTimeout` | `0` | 若在该段时间间隔内未写入任何数据,将关闭连接。 | | `StrictMaxConcurrentStreams` | `false` | 设置服务器的 `SETTINGS_MAX_CONCURRENT_STREAMS` 是否应该被全局使用。 | -| `DialTimeout` | `1s` | 与主机建立新连接的超时时间。 | -| `MaxIdleConnDuration` | `0` | 闲置的长连接在该段时间后关闭。 | -| `DisableKeepAlive` | `false` | 是否在每次请求后关闭连接。 | -| `Dialer` | `netpoll.NewDialer()` | 用于设置拨号器。 | -| `TLSConfig` | `nil` | `TLS` 配置 | -| `RetryConfig` | `nil` | 所有与重试有关的配置 | +| `DialTimeout` | `1s` | 与主机建立新连接的超时时间。 | +| `MaxIdleConnDuration` | `0` | 闲置的长连接在该段时间后关闭。 | +| `DisableKeepAlive` | `false` | 是否在每次请求后关闭连接。 | +| `Dialer` | `netpoll.NewDialer()` | 用于设置拨号器。 | +| `TLSConfig` | `nil` | `TLS` 配置 | +| `RetryConfig` | `nil` | 所有与重试有关的配置 | 示例代码: @@ -345,7 +345,7 @@ import ( "github.com/cloudwego/hertz/pkg/app/server" "github.com/cloudwego/hertz/pkg/network/standard" "github.com/cloudwego/hertz/pkg/protocol" - + "github.com/hertz-contrib/http2/config" "github.com/hertz-contrib/http2/factory" ) diff --git a/content/zh/docs/hertz/tutorials/basic-feature/protocol/http3.md b/content/zh/docs/hertz/tutorials/basic-feature/protocol/http3.md index 6b04cc1d08..ec3d7e1cf2 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/protocol/http3.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/protocol/http3.md @@ -4,7 +4,6 @@ date: 2023-07-29 weight: 3 keywords: ["QUIC", "HTTP", "HTTP3"] description: "Hertz-HTTP3 基于 quic-go 实现。" - --- QUIC 协议是一种传输层网络协议,提供与 TLS/SSL 相当的安全性,同时具有更低的连接和传输延迟。QUIC 目前主要应用于 HTTP 协议,HTTP-over-QUIC 协议即为 HTTP/3,是 HTTP 协议的第三个正式版本。 @@ -19,7 +18,7 @@ Hertz-HTTP3 基于 [quic-go](https://github.com/quic-go/quic-go) 实现,[实 go get github.com/hertz-contrib/http3 ``` ->注意:go 版本需大于等于 1.19。 +> 注意:go 版本需大于等于 1.19。 ## 网络层与协议层注册 @@ -40,19 +39,19 @@ h.AddProtocol(suite.HTTP3, factory.NewServerFactory(&http3.Option{})) ### 服务端 -| 配置 | 说明 | -| :----------------- | -------------------------------------------- | -| WithTransport | 设置 HTTP3 实现的网络库 `quic.NewTransporter` | -| WithAltTransport | 设置备用网络库 `netpoll` 或 `go net`,适用于同时在 TCP 和 QUIC 监听的场景 | -| WithALPN | 设置是否启用 ALPN | -| WithTLS | 设置 TLS 配置 | -| WithHostPorts | 设置开启服务的域名和端口号 | +| 配置 | 说明 | +| :--------------- | ------------------------------------------------------------------------- | +| WithTransport | 设置 HTTP3 实现的网络库 `quic.NewTransporter` | +| WithAltTransport | 设置备用网络库 `netpoll` 或 `go net`,适用于同时在 TCP 和 QUIC 监听的场景 | +| WithALPN | 设置是否启用 ALPN | +| WithTLS | 设置 TLS 配置 | +| WithHostPorts | 设置开启服务的域名和端口号 | ## 示例代码 ### 服务端 ->注意:QUIC 协议依赖于 TLS 协议,因此需要提供 TLS 配置。 +> 注意:QUIC 协议依赖于 TLS 协议,因此需要提供 TLS 配置。 ```go package main diff --git a/content/zh/docs/hertz/tutorials/basic-feature/protocol/sse.md b/content/zh/docs/hertz/tutorials/basic-feature/protocol/sse.md index 5f18e531f4..1bcbaae62e 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/protocol/sse.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/protocol/sse.md @@ -4,7 +4,6 @@ date: 2023-05-12 weight: 6 keywords: ["SSE", "HTTP", "Server-Sent Events"] description: "Hertz 支持 SSE,允许服务器端通过简单的 HTTP 响应向客户端发送事件。" - --- SSE 是 Server-Sent Events 的缩写,是一种服务器推送技术,它允许服务器端通过简单的 HTTP 响应向客户端发送事件。 @@ -30,9 +29,9 @@ import ( "context" "net/http" "time" - + "github.com/hertz-contrib/sse" - + "github.com/cloudwego/hertz/pkg/app" "github.com/cloudwego/hertz/pkg/app/server" "github.com/cloudwego/hertz/pkg/common/hlog" @@ -40,12 +39,12 @@ import ( func main() { h := server.Default() - + h.GET("/sse", func(ctx context.Context, c *app.RequestContext) { // 客户端可以通过 Last-Event-ID 告知服务器收到的最后一个事件 lastEventID := sse.GetLastEventID(c) hlog.CtxInfof(ctx, "last event ID: %s", lastEventID) - + // 在第一次渲染调用之前必须先行设置状态代码和响应头文件 c.SetStatusCode(http.StatusOK) s := sse.NewStream(c) @@ -60,7 +59,7 @@ func main() { } } }) - + h.Spin() } ``` @@ -82,9 +81,9 @@ import ( var wg sync.WaitGroup func main() { - wg.Add(2) + wg.Add(2) go func() { - // 传入 server 端 URL 初始化客户端 + // 传入 server 端 URL 初始化客户端 c := sse.NewClient("http://127.0.0.1:8888/sse") // 连接到服务端的时候触发 @@ -121,7 +120,7 @@ func main() { }() go func() { - // 传入 server 端 URL 初始化客户端 + // 传入 server 端 URL 初始化客户端 c := sse.NewClient("http://127.0.0.1:8888/sse") // 连接到服务端的时候触发 @@ -182,14 +181,14 @@ package main func main() { h := server.Default() - + h.GET("/sse", func(ctx context.Context, c *app.RequestContext) { c.SetStatusCode(http.StatusOK) c.Response.Header.Set("X-Accel-Buffering", "no") s := sse.NewStream(c) // ... }) - + } ``` @@ -213,7 +212,7 @@ type Event struct { 函数签名: ```go -func (c *Stream) Publish(event *Event) error +func (c *Stream) Publish(event *Event) error ``` ### GetLastEventID diff --git a/content/zh/docs/hertz/tutorials/basic-feature/protocol/tls.md b/content/zh/docs/hertz/tutorials/basic-feature/protocol/tls.md index 75f57eb0f6..3c38570859 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/protocol/tls.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/protocol/tls.md @@ -4,7 +4,6 @@ date: 2022-11-06 weight: 5 keywords: ["TLS", "HTTP"] description: "Hertz 支持 TLS 安全传输,帮助用户实现数据的保密性和完整性。" - --- Hertz 支持 TLS 安全传输,帮助用户实现了数据的保密性和完整性。 @@ -13,14 +12,14 @@ Hertz 支持 TLS 安全传输,帮助用户实现了数据的保密性和完整 在 `tls.Config` 中,服务端和客户端都可使用的参数如下: -| 参数名 | 介绍 | -|:---------------------:|:---------------------------------------| +| 参数名 | 介绍 | +| :-------------------: | :--------------------------------------------------------------------- | | Certificates | 用于添加证书,可以配置多个证书。
两端自动选择第一个证书进行验证。 | -| VerifyPeerCertificate | 用于验证对端证书。
在任意一端证书验证后调用。 | -| VerifyConnection | 在两端证书均验证后,进行 TLS 连接验证。 | -| NextProtos | 用于设置支持的应用层协议。 | -| CipherSuites | 用于协商加密策略,支持 TLS 1.0-1.2。 | -| MaxVersion | 用于设置 TLS 支持的最大版本,目前是 1.3。 | +| VerifyPeerCertificate | 用于验证对端证书。
在任意一端证书验证后调用。 | +| VerifyConnection | 在两端证书均验证后,进行 TLS 连接验证。 | +| NextProtos | 用于设置支持的应用层协议。 | +| CipherSuites | 用于协商加密策略,支持 TLS 1.0-1.2。 | +| MaxVersion | 用于设置 TLS 支持的最大版本,目前是 1.3。 | ## 服务端 @@ -42,13 +41,13 @@ func WithTLS(cfg *tls.Config) config.Option { 在 `tls.Config` 中,除了上述基本参数,服务端可以配置的参数如下: -| 参数名 | 介绍 | -|:---------------------:|:---------------------------------------------------------------------| -| GetCertificate | 基于客户端 SNI 信息或证书集为空时,返回证书。 | - | GetClientCertificate | 用于服务端要求验证客户端证书时,返回客户端证书。 | - | GetConfigForClient | 当服务端从客户端接收了 ClientHello 后,返回配置信息。
如果返回的是非空的配置信息,将会被用于这次 TLS 连接。 | - | ClientAuth | 用于客户端验证策略设置,默认为 `NoClientCert`。 | - | ClientCAs | 当启用了 `ClientAuth`, 用于验证客户端证书的真实性。 | +| 参数名 | 介绍 | +| :------------------: | :--------------------------------------------------------------------------------------------------------------- | +| GetCertificate | 基于客户端 SNI 信息或证书集为空时,返回证书。 | +| GetClientCertificate | 用于服务端要求验证客户端证书时,返回客户端证书。 | +| GetConfigForClient | 当服务端从客户端接收了 ClientHello 后,返回配置信息。
如果返回的是非空的配置信息,将会被用于这次 TLS 连接。 | +| ClientAuth | 用于客户端验证策略设置,默认为 `NoClientCert`。 | +| ClientCAs | 当启用了 `ClientAuth`, 用于验证客户端证书的真实性。 | 服务器端 TLS 主要流程: @@ -138,11 +137,11 @@ func main() { 在 `tls.Config` 中,除了上述基本参数,客户端可以配置的参数如下: -| 参数名 | 介绍 | -|:---------------------:|:-------------------| -| ServerName | 根据返回的证书信息验证主机名。 | -| InsecureSkipVerify | 用于客户端是否开启服务端的证书验证。 | -| RootCAs | 用于客户端验证服务端的证书。 | +| 参数名 | 介绍 | +| :----------------: | :----------------------------------- | +| ServerName | 根据返回的证书信息验证主机名。 | +| InsecureSkipVerify | 用于客户端是否开启服务端的证书验证。 | +| RootCAs | 用于客户端验证服务端的证书。 | 客户端 TLS 主要流程: @@ -376,8 +375,8 @@ func main() { InsecureSkipVerify: true, } c, err := client.NewClient( - client.WithTLSConfig(clientCfg), - client.WithDialer(standard.NewDialer()), + client.WithTLSConfig(clientCfg), + client.WithDialer(standard.NewDialer()), ) } ``` diff --git a/content/zh/docs/hertz/tutorials/basic-feature/protocol/websocket.md b/content/zh/docs/hertz/tutorials/basic-feature/protocol/websocket.md index b800364d88..ae5806511c 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/protocol/websocket.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/protocol/websocket.md @@ -1,11 +1,11 @@ --- title: "Websocket" -date: 2022-09-13 +date: 2022-09-13 weight: 4 keywords: ["WebSocket", "HTTP", "hijack", "TCP"] description: "Hertz 基于 hijack 的方式实现了对 WebSocket 的支持。" - --- + WebSocket 是一种可以在单个 TCP 连接上进行全双工通信,位于 OSI 模型的应用层。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就可以创建持久性的连接,并进行双向数据传输。 Hertz 提供了 WebSocket 的支持,参考 [gorilla/websocket](http://github.com/gorilla/websocket) 库使用 `hijack` 的方式在 Hertz 进行了适配,用法和参数基本保持一致。 @@ -91,15 +91,15 @@ go run server.go 这部分将围绕 `websocket.HertzUpgrader` 结构展开说明。 -| 参数 | 介绍 | -| ------------------- | ------------------------------------------------------------ | -| `ReadBufferSize` | 用于设置输入缓冲区的大小,单位为字节。如果缓冲区大小为零,那么就使用 HTTP 服务器分配的大小。输入缓冲区大小并不限制可以接收的信息的大小。 | -| `WriteBufferSize` | 用于设置输出缓冲区的大小,单位为字节。如果缓冲区大小为零,那么就使用 HTTP 服务器分配的大小。输出缓冲区大小并不限制可以发送的信息的大小。 | -| `WriteBufferPool` | 用于设置写操作的缓冲池。 | +| 参数 | 介绍 | +| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `ReadBufferSize` | 用于设置输入缓冲区的大小,单位为字节。如果缓冲区大小为零,那么就使用 HTTP 服务器分配的大小。输入缓冲区大小并不限制可以接收的信息的大小。 | +| `WriteBufferSize` | 用于设置输出缓冲区的大小,单位为字节。如果缓冲区大小为零,那么就使用 HTTP 服务器分配的大小。输出缓冲区大小并不限制可以发送的信息的大小。 | +| `WriteBufferPool` | 用于设置写操作的缓冲池。 | | `Subprotocols` | 用于按优先顺序设置服务器支持的协议。如果这个字段不是 nil,那么 Upgrade 方法通过选择这个列表中与客户端请求的协议的第一个匹配来协商一个子协议。如果没有匹配,那么就不协商协议(Sec-Websocket-Protocol 头不包括在握手响应中)。 | -| `Error` | 用于设置生成 HTTP 错误响应的函数。 | -| `CheckOrigin` | 用于设置针对请求的 Origin 头的校验函数,如果请求的 Origin 头是可接受的,CheckOrigin 返回 true。 | -| `EnableCompression` | 用于设置服务器是否应该尝试协商每个消息的压缩(RFC 7692)。将此值设置为 true 并不能保证压缩会被支持。 | +| `Error` | 用于设置生成 HTTP 错误响应的函数。 | +| `CheckOrigin` | 用于设置针对请求的 Origin 头的校验函数,如果请求的 Origin 头是可接受的,CheckOrigin 返回 true。 | +| `EnableCompression` | 用于设置服务器是否应该尝试协商每个消息的压缩(RFC 7692)。将此值设置为 true 并不能保证压缩会被支持。 | ### WriteBufferPool @@ -224,7 +224,7 @@ func echo(_ context.Context, c *app.RequestContext) { ``` ## NoHijackConnPool -> + > Hertz 连接劫持时所使用的 hijack conn 是池化管理的,因此被劫持的连接在 websocket 中使用的时候,不支持异步操作。 劫持的连接仅能被关闭一次,第二次关闭会导致空指针异常。 diff --git a/content/zh/docs/hertz/tutorials/basic-feature/proxy.md b/content/zh/docs/hertz/tutorials/basic-feature/proxy.md index 7909523714..a774f2aae1 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/proxy.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/proxy.md @@ -4,7 +4,6 @@ date: 2022-09-08 weight: 12 keywords: ["正向代理", "反向代理"] description: "Hertz 提供的正向代理和反向代理能力。" - --- ## 正向代理 @@ -124,17 +123,17 @@ func NewSingleHostReverseProxy(target string, opts ...config.Option) (*reversePr ``` > - `NewSingleHostReverseProxy` 方法如果没有设置 `config.ClientOption` 将会使用默认的全局 `client.Client` 实例, -如果设置了 `config.ClientOption` 将会初始化一个 `client.Client` 实例。 -如果你需要共享一个 `client.Client` 实例,可以使用 `ReverseProxy.SetClient` 来设置。 +> 如果设置了 `config.ClientOption` 将会初始化一个 `client.Client` 实例。 +> 如果你需要共享一个 `client.Client` 实例,可以使用 `ReverseProxy.SetClient` 来设置。 > - 反向代理会重置响应头,如果在请求之前修改了响应头将不会生效。 我们提供了 `SetXxx()` 函数用于设置私有属性 -| 方法 | 描述 | -|---------------------|-------------------------------------| -| `SetDirector` | 用于指定 protocol.Request | -| `SetClient` | 用于指定转发的客户端 | -| `SetModifyResponse` | 用于指定响应修改方法 | +| 方法 | 描述 | +| ------------------- | ------------------------------------------------------ | +| `SetDirector` | 用于指定 protocol.Request | +| `SetClient` | 用于指定转发的客户端 | +| `SetModifyResponse` | 用于指定响应修改方法 | | `SetErrorHandler` | 用于指定处理到达后台的错误或来自 modifyResponse 的错误 | ### 示例 @@ -231,19 +230,19 @@ func main() { #### 配置 -| 配置 | 默认值 | 描述 | -|----------------|---------------------------|--------------| -| `WithDirector` | `nil` | 自定义转发头 | +| 配置 | 默认值 | 描述 | +| -------------- | ------------------------- | --------------- | +| `WithDirector` | `nil` | 自定义转发头 | | `WithDialer` | `gorillaws.DefaultDialer` | 自定义 Dialer | | `WithUpgrader` | `hzws.HertzUpgrader` | 自定义 Upgrader | ### 更多示例 -| 用途 | 示例代码 | -|--------------|-------------------------------------------------------------------------------------------| +| 用途 | 示例代码 | +| -------------- | ----------------------------------------------------------------------------------------- | | 代理 tls | [code](https://github.com/cloudwego/hertz-examples/tree/main/reverseproxy/tls) | -| 使用服务发现 | [code](https://github.com/cloudwego/hertz-examples/tree/main/reverseproxy/discovery) | -| 配合中间件使用 | [code](https://github.com/cloudwego/hertz-examples/tree/main/reverseproxy/use_middleware) | +| 使用服务发现 | [code](https://github.com/cloudwego/hertz-examples/tree/main/reverseproxy/discovery) | +| 配合中间件使用 | [code](https://github.com/cloudwego/hertz-examples/tree/main/reverseproxy/use_middleware) | | 代理 websocket | [code](https://github.com/cloudwego/hertz-examples/tree/main/reverseproxy/websocket) | 更多使用方法可参考如下 [examples](https://github.com/cloudwego/hertz-examples/tree/main/reverseproxy)。 diff --git a/content/zh/docs/hertz/tutorials/basic-feature/render.md b/content/zh/docs/hertz/tutorials/basic-feature/render.md index e1b67c364a..0c1f79a991 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/render.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/render.md @@ -1,8 +1,9 @@ --- -title: '渲染' +title: "渲染" date: 2023-06-01 weight: 18 -keywords: ["渲染", "JSON", "Data", "HTML", "Protobuf", "Text", "XML", "自定义渲染"] +keywords: + ["渲染", "JSON", "Data", "HTML", "Protobuf", "Text", "XML", "自定义渲染"] description: "Hertz 提供的渲染能力。" --- @@ -93,16 +94,16 @@ func main() { msg.Company = "company" msg.Location = "location" msg.Number = 123 - + c.IndentedJSON(consts.StatusOK, msg) - /* + /* will output : { "Company": "company", "Location": "location", "Number": 123 - } + } */ - + h.Spin() } ``` @@ -291,7 +292,7 @@ func main() { h.GET("someText", func(ctx context.Context, c *app.RequestContext) { c.String(consts.StatusOK, "message", "hello,world") }) - + h.Spin() } ``` diff --git a/content/zh/docs/hertz/tutorials/basic-feature/retry.md b/content/zh/docs/hertz/tutorials/basic-feature/retry.md index f8711d3682..e204300186 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/retry.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/retry.md @@ -4,7 +4,6 @@ date: 2022-10-01 weight: 13 keywords: ["重试", "Client"] description: "Hertz 为用户提供的自定义重试逻辑。" - --- Hertz 为用户提供了自定义的重试逻辑,下面来看一下 Client 的 Retry 使用方法。**注意:Hertz 版本 >= v0.4.0** @@ -30,13 +29,13 @@ func main() { } ``` -| 配置名称 | 类型 | 介绍 | -| :------------------ | :----------------------------------------------------------- | :----------------------------------------------------------- | -| WithMaxAttemptTimes | uint | 用于设置最大尝试次数,默认 1 次(即只请求 1 次不重试) | -| WithInitDelay | time.Duration | 用于设置初始延迟时间,默认 1ms | -| WithMaxDelay | time.Duration | 用于设置最大延迟时间,默认 100ms | -| WithMaxJitter | time.Duration | 用于设置最大扰动时间,需要配合 RandomDelayPolicy 使用,会生成不超过最大扰动时间的随机时间,默认 20ms | -| WithDelayPolicy | type DelayPolicyFunc func(attempts uint, err error, retryConfig *Config) time.Duration | 用于设置延迟策略,可以使用以下四种的任意结合,FixedDelayPolicy, BackOffDelayPolicy, RandomDelayPolicy, DefaultDelayPolicy([详情见下一小节:**延迟策略**](#延迟策略))默认使用 DefaultDelayPolicy(即重试延迟为 0) | +| 配置名称 | 类型 | 介绍 | +| :------------------ | :-------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| WithMaxAttemptTimes | uint | 用于设置最大尝试次数,默认 1 次(即只请求 1 次不重试) | +| WithInitDelay | time.Duration | 用于设置初始延迟时间,默认 1ms | +| WithMaxDelay | time.Duration | 用于设置最大延迟时间,默认 100ms | +| WithMaxJitter | time.Duration | 用于设置最大扰动时间,需要配合 RandomDelayPolicy 使用,会生成不超过最大扰动时间的随机时间,默认 20ms | +| WithDelayPolicy | type DelayPolicyFunc func(attempts uint, err error, retryConfig \*Config) time.Duration | 用于设置延迟策略,可以使用以下四种的任意结合,FixedDelayPolicy, BackOffDelayPolicy, RandomDelayPolicy, DefaultDelayPolicy([详情见下一小节:**延迟策略**](#延迟策略))默认使用 DefaultDelayPolicy(即重试延迟为 0) | ### 延迟策略 @@ -52,13 +51,13 @@ cli, err := client.NewClient( ) ``` -| 函数名称 | 说明 | -| :----------------- | :----------------------------------------------------------- | +| 函数名称 | 说明 | +| :----------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | CombineDelay | 用于将下面四种策略进行任意组合,将所选策略计算出的值进行加和。当你只需要下面四种策略中的一种时,你可以选择使用 CombineDelay 或选择直接将任意一种策略传入 WithDelayPolicy 作为参数 | -| FixedDelayPolicy | 用于设置固定延迟时间,使用 WithInitDelay 设置的值,来生成等值的延迟时间 | -| BackOffDelayPolicy | 用于设置指数级延迟时间,使用 WithInitDelay 设置的值,根据当前是第几次重试,指数级生成延迟时间 | -| RandomDelayPolicy | 用于设置随机延迟时间,使用 WithMaxJitter 设置的值,生成不超过该值的随机延迟时间 | -| DefaultDelayPolicy | 用于设置默认延迟时间,返回 0,一般单独使用,和其他策略结合没有效果 | +| FixedDelayPolicy | 用于设置固定延迟时间,使用 WithInitDelay 设置的值,来生成等值的延迟时间 | +| BackOffDelayPolicy | 用于设置指数级延迟时间,使用 WithInitDelay 设置的值,根据当前是第几次重试,指数级生成延迟时间 | +| RandomDelayPolicy | 用于设置随机延迟时间,使用 WithMaxJitter 设置的值,生成不超过该值的随机延迟时间 | +| DefaultDelayPolicy | 用于设置默认延迟时间,返回 0,一般单独使用,和其他策略结合没有效果 | ### 完整示例 @@ -108,7 +107,7 @@ cli.SetRetryIfFunc(func(req *protocol.Request, resp *protocol.Response, err erro }) ``` -需要注意的是,如果你没有设置 `client.SetRetryIfFunc()`。我们将会按照 Hertz 默认的重试发生条件进行判断,即判断请求是否满足下面的 `DefaultRetryIf()` 函数并且判断该调用是否是幂等调用(幂等调用:即 [pkg/protocol/http1/client.go::Do()](https://github.com/cloudwego/hertz/blob/develop/pkg/protocol/http1/client.go#L328 ) 和 [pkg/protocol/http1/client.go::doNonNilReqResp()](https://github.com/cloudwego/hertz/blob/develop/pkg/protocol/http1/client.go#L411) 中 `canIdempotentRetry` 为 true 的 [情况](#table1)) +需要注意的是,如果你没有设置 `client.SetRetryIfFunc()`。我们将会按照 Hertz 默认的重试发生条件进行判断,即判断请求是否满足下面的 `DefaultRetryIf()` 函数并且判断该调用是否是幂等调用(幂等调用:即 [pkg/protocol/http1/client.go::Do()](https://github.com/cloudwego/hertz/blob/develop/pkg/protocol/http1/client.go#L328) 和 [pkg/protocol/http1/client.go::doNonNilReqResp()](https://github.com/cloudwego/hertz/blob/develop/pkg/protocol/http1/client.go#L411) 中 `canIdempotentRetry` 为 true 的 [情况](#table1)) ```Go // DefaultRetryIf Default retry condition, mainly used for idempotent requests. @@ -147,11 +146,11 @@ func isIdempotent(req *protocol.Request, resp *protocol.Response, err error) boo
Table - 1 Hertz 源码 [doNonNilReqResp()](https://github.com/cloudwego/hertz/blob/develop/pkg/protocol/http1/client.go#L411) 中 `canIdempotentRetry` 为 true 的情况 -| doNonNilReqResp() 返回 true 的情况 | -| ------------------------------------------------------------ | -| err = conn.SetWriteDeadline(currentTime.Add(c.WriteTimeout)) | -| err = reqI.Write(req, zw) | -| err = reqI.ProxyWrite(req, zw) | -| err = zw.Flush() | -| err = conn.SetReadTimeout(c.ReadTimeout) | +| doNonNilReqResp() 返回 true 的情况 | +| ----------------------------------------------------------------------------------------------------------- | +| err = conn.SetWriteDeadline(currentTime.Add(c.WriteTimeout)) | +| err = reqI.Write(req, zw) | +| err = reqI.ProxyWrite(req, zw) | +| err = zw.Flush() | +| err = conn.SetReadTimeout(c.ReadTimeout) | | ( err = respI.ReadHeaderAndLimitBody() \|\| err = respI.ReadBodyStream() ) && (err != errs.ErrBodyTooLarge) | diff --git a/content/zh/docs/hertz/tutorials/basic-feature/route.md b/content/zh/docs/hertz/tutorials/basic-feature/route.md index f700d19683..94f9578da8 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/route.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/route.md @@ -2,27 +2,35 @@ title: "路由" date: 2022-09-06 weight: 2 -keywords: ["路由", "路由组", "静态路由", "参数路由", "路由优先级", "NoRoute", "NoMethod"] +keywords: + [ + "路由", + "路由组", + "静态路由", + "参数路由", + "路由优先级", + "NoRoute", + "NoMethod", + ] description: "Hertz 提供的路由功能。" - --- ## 路由注册 Hertz 提供了 `GET`、`POST`、`PUT`、`DELETE`、`ANY` 等方法用于注册路由。 -| 方法 | 介绍 | -| ------------ | ------------ | -| `Hertz.GET` | 用于注册 HTTP Method 为 GET 的方法 | -| `Hertz.POST` | 用于注册 HTTP Method 为 POST 的方法 | -| `Hertz.DELETE` | 用于注册 HTTP Method 为 DELETE 的方法 | -| `Hertz.PUT` | 用于注册 HTTP Method 为 PUT 的方法 | -| `Hertz.PATCH` | 用于注册 HTTP Method 为 PATCH 的方法 | -| `Hertz.HEAD` | 用于注册 HTTP Method 为 HEAD 的方法 | -| `Hertz.OPTIONS` | 用于注册 HTTP Method 为 OPTIONS 的方法 | -| `Hertz.Handle` | 这个方法支持用户手动传入 HTTP Method 用来注册方法,当用于注册普通的 HTTP Method 方法时和上述的方法作用是一致的,并且这个方法同时也支持用于注册自定义 HTTP Method 方法 | -| `Hertz.Any` | 用于注册所有 HTTP Method 方法 | -| `Hertz.StaticFile/Static/StaticFS` | 用于注册静态文件 | +| 方法 | 介绍 | +| ---------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `Hertz.GET` | 用于注册 HTTP Method 为 GET 的方法 | +| `Hertz.POST` | 用于注册 HTTP Method 为 POST 的方法 | +| `Hertz.DELETE` | 用于注册 HTTP Method 为 DELETE 的方法 | +| `Hertz.PUT` | 用于注册 HTTP Method 为 PUT 的方法 | +| `Hertz.PATCH` | 用于注册 HTTP Method 为 PATCH 的方法 | +| `Hertz.HEAD` | 用于注册 HTTP Method 为 HEAD 的方法 | +| `Hertz.OPTIONS` | 用于注册 HTTP Method 为 OPTIONS 的方法 | +| `Hertz.Handle` | 这个方法支持用户手动传入 HTTP Method 用来注册方法,当用于注册普通的 HTTP Method 方法时和上述的方法作用是一致的,并且这个方法同时也支持用于注册自定义 HTTP Method 方法 | +| `Hertz.Any` | 用于注册所有 HTTP Method 方法 | +| `Hertz.StaticFile/Static/StaticFS` | 用于注册静态文件 | 示例代码: @@ -181,12 +189,12 @@ Hertz 支持使用 `:name` 这样的命名参数设置路由,并且命名参 如果我们设置 `/user/:name` 路由,匹配情况如下 -| 路径 | 是否匹配 | -| ---- | ---- | -| /user/gordon | 匹配 | -| /user/you | 匹配 | -| /user/gordon/profile | 不匹配 | -| /user/ | 不匹配 | +| 路径 | 是否匹配 | +| -------------------- | -------- | +| /user/gordon | 匹配 | +| /user/you | 匹配 | +| /user/gordon/profile | 不匹配 | +| /user/ | 不匹配 | 通过使用 `RequestContext.Param` 方法,我们可以获取路由中携带的参数。 @@ -221,11 +229,11 @@ Hertz 支持使用 `*path` 这样的通配参数设置路由,并且通配参 如果我们设置 `/src/*path` 路由,匹配情况如下 -| 路径 | 是否匹配 | -| ---- | ---- | -| /src/ | 匹配 | -| /src/somefile.go | 匹配 | -| /src/subdir/somefile.go | 匹配 | +| 路径 | 是否匹配 | +| ----------------------- | -------- | +| /src/ | 匹配 | +| /src/somefile.go | 匹配 | +| /src/subdir/somefile.go | 匹配 | 通过使用 `RequestContext.Param` 方法,我们可以获取路由中携带的参数。 @@ -372,11 +380,11 @@ func main() { Hertz 在默认情况下会根据请求 path 末尾的 `/` 自动进行转发。如果 router 中只有 /foo/,那么请求 /foo 会被自动重定向到 /foo/;如果 router 中只有 /foo,那么 /foo/ 会被重定向到 /foo。 -这样的请求除 `GET` 以外的请求方法都会触发 `307 Temporary Redirect` 状态码,而 `GET` 请求会触发 `301 Moved Permanently` 状态码。 +这样的请求除 `GET` 以外的请求方法都会触发 `307 Temporary Redirect` 状态码,而 `GET` 请求会触发 `301 Moved Permanently` 状态码。 可以在配置中取消,如下: -````go +```go package main import "github.com/cloudwego/hertz/pkg/app/server" @@ -385,6 +393,6 @@ func main() { h := server.New(server.WithRedirectTrailingSlash(false)) ... } -```` +``` 获取更多配置相关信息:[配置说明](/zh/docs/hertz/reference/config/) diff --git a/content/zh/docs/hertz/tutorials/basic-feature/unit-test.md b/content/zh/docs/hertz/tutorials/basic-feature/unit-test.md index 91fa560caf..a82bf97daf 100644 --- a/content/zh/docs/hertz/tutorials/basic-feature/unit-test.md +++ b/content/zh/docs/hertz/tutorials/basic-feature/unit-test.md @@ -4,7 +4,6 @@ date: 2022-05-23 weight: 15 keywords: ["单测"] description: "Hertz 为用户提供的单元测试能力。" - --- 一个好的项目的构建离不开单元测试。为了帮助使用者构建出好的项目,hertz 当然也提供了单元测试的工具。 @@ -146,15 +145,15 @@ type ResponseRecorder struct { 该对象提供的方法如下: -|函数签名 | 说明 | -|:--|:--| -|`func NewRecorder() *ResponseRecorder` |返回初始化后的 `ResponseRecorder` 对象 | -|`func (rw *ResponseRecorder) Header() *protocol.ResponseHeader` |返回 `ResponseRecorder.header` | -|`func (rw *ResponseRecorder) Write(buf []byte) (int, error)` |将 `[]byte` 类型的数据写入 `ResponseRecorder.Body` | -|`func (rw *ResponseRecorder) WriteString(str string) (int, error)` |将 `string` 类型的数据写入 `ResponseRecorder.Body` | -|`func (rw *ResponseRecorder) WriteHeader(code int)`|设置 `ResponseRecorder.Code` 以及 `ResponseRecorder.header.SetStatusCode(code)` | -|`func (rw *ResponseRecorder) Flush()` |实现了 `http.Flusher`,将 `ResponseRecorder.Flushed` 设置为 true | -|`func (rw *ResponseRecorder) Result() *protocol.Response` | 返回 handler 生成的响应信息,至少包含 StatusCode, Header, Body 以及可选的 Trailer,未来将支持返回更多的响应信息 | +| 函数签名 | 说明 | +| :----------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------- | +| `func NewRecorder() *ResponseRecorder` | 返回初始化后的 `ResponseRecorder` 对象 | +| `func (rw *ResponseRecorder) Header() *protocol.ResponseHeader` | 返回 `ResponseRecorder.header` | +| `func (rw *ResponseRecorder) Write(buf []byte) (int, error)` | 将 `[]byte` 类型的数据写入 `ResponseRecorder.Body` | +| `func (rw *ResponseRecorder) WriteString(str string) (int, error)` | 将 `string` 类型的数据写入 `ResponseRecorder.Body` | +| `func (rw *ResponseRecorder) WriteHeader(code int)` | 设置 `ResponseRecorder.Code` 以及 `ResponseRecorder.header.SetStatusCode(code)` | +| `func (rw *ResponseRecorder) Flush()` | 实现了 `http.Flusher`,将 `ResponseRecorder.Flushed` 设置为 true | +| `func (rw *ResponseRecorder) Result() *protocol.Response` | 返回 handler 生成的响应信息,至少包含 StatusCode, Header, Body 以及可选的 Trailer,未来将支持返回更多的响应信息 | ## 与业务 handler 配合使用 diff --git a/content/zh/docs/hertz/tutorials/example/_index.md b/content/zh/docs/hertz/tutorials/example/_index.md index daa6788adb..1629ec5927 100644 --- a/content/zh/docs/hertz/tutorials/example/_index.md +++ b/content/zh/docs/hertz/tutorials/example/_index.md @@ -4,7 +4,6 @@ linkTitle: "代码示例" weight: 1 keywords: ["Hertz", "hertz-examples", "Bizdemo", "Server", "Client", "Hz"] description: "Hertz 提供了一系列示例代码旨在帮助用户快速上手 Hertz 并了解 Hertz 的特性。" - --- Hertz 提供了一系列示例代码旨在帮助用户快速上手 Hertz 并了解 Hertz 的特性,参考 [hertz-examples](https://github.com/cloudwego/hertz-examples) 以获取更多信息。 @@ -12,15 +11,19 @@ Hertz 提供了一系列示例代码旨在帮助用户快速上手 Hertz 并了 ## Bizdemo ### hertz_gorm + - [hertz_gorm](https://github.com/cloudwego/hertz-examples/tree/main/bizdemo/hertz_gorm) :在 hertz server 中使用 gorm 的示例 ### hertz_gorm_gen + - [hertz_gorm_gen](https://github.com/cloudwego/hertz-examples/tree/main/bizdemo/hertz_gorm_gen) :在 hertz server 中使用 gorm/gen & proto IDL 的示例 ### hertz_jwt + - [hertz_jwt](https://github.com/cloudwego/hertz-examples/tree/main/bizdemo/hertz_jwt) :在 hertz server 中使用 jwt 的示例 ### hertz_session + - [hertz_session](https://github.com/cloudwego/hertz-examples/tree/main/bizdemo/hertz_session) :在 hertz server 中使用分布式 session 和 csrf 的示例 ### tiktok_demo @@ -34,12 +37,15 @@ Hertz 提供了一系列示例代码旨在帮助用户快速上手 Hertz 并了 ## Server ### 启动 Hertz + - [hello](https://github.com/cloudwego/hertz-examples/tree/main/hello) :启动对于 hertz 来说相当于 "hello world" 的示例 ### 配置 + - [config](https://github.com/cloudwego/hertz-examples/tree/main/config) :配置 hertz server 的示例 ### 协议 + - [HTTP1](https://github.com/cloudwego/hertz-examples/tree/main/protocol/http1) : hertz 使用 HTTP1 协议的示例 - [TLS](https://github.com/cloudwego/hertz-examples/tree/main/protocol/tls) : hertz 使用 TLS 协议的示例 - [HTTP2](https://github.com/hertz-contrib/http2/tree/main/examples) : hertz 使用 HTTP2 协议的示例 @@ -48,9 +54,11 @@ Hertz 提供了一系列示例代码旨在帮助用户快速上手 Hertz 并了 - [SSE](https://github.com/hertz-contrib/sse/tree/main/examples) : hertz 使用 SSE 协议的示例 ### 路由 + - [Route](https://github.com/cloudwego/hertz-examples/tree/main/route) :注册路由、使用路由组、参数路由的示例 ### 中间件 + - [basic_auth](https://github.com/cloudwego/hertz-examples/tree/main/middleware/basicauth) :使用 basic auth 中间件的示例 - [CORS](https://github.com/cloudwego/hertz-examples/tree/main/middleware/CORS) :使用 CORS 中间件的示例 - [custom](https://github.com/cloudwego/hertz-examples/tree/main/middleware/custom) :自定义中间件的示例 @@ -74,48 +82,63 @@ Hertz 提供了一系列示例代码旨在帮助用户快速上手 Hertz 并了 - [Paseto](https://github.com/hertz-contrib/paseto/tree/main/example) :使用 Paseto 中间件的示例 ### 参数绑定及验证 + - [binding](https://github.com/cloudwego/hertz-examples/tree/main/binding) :参数绑定及验证的示例 ### 获取参数 + - [parameters](https://github.com/cloudwego/hertz-examples/tree/main/parameter) :获取 query、form、cookie 等参数的示例 ### 文件 + - [file](https://github.com/cloudwego/hertz-examples/tree/main/file) :关于如何上传,下载文件和搭建静态文件服务的示例 ### 渲染 + - [render](https://github.com/cloudwego/hertz-examples/tree/main/render) :渲染 json, html, protobuf 的示例 ### 重定向 + - [redirect](https://github.com/cloudwego/hertz-examples/tree/main/redirect) :重定向到内部/外部 URI 的示例 ### 流式读/写 + - [streaming](https://github.com/cloudwego/hertz-examples/tree/main/streaming) :使用 hertz server 流式读/写的示例 ### 优雅退出 + - [graceful_shutdown](https://github.com/cloudwego/hertz-examples/tree/main/graceful_shutdown) :hertz server 优雅退出的示例 ### 单元测试 + - [unit_test](https://github.com/cloudwego/hertz-examples/tree/main/unit_test) :使用 hertz 提供的接口不经过网络传输编写单元测试的示例 ### 链路追踪 + - [tracer](https://github.com/cloudwego/hertz-examples/tree/main/tracer) :hertz 使用 Jaeger 进行链路追踪的示例 ### 监控 + - [monitoring](https://github.com/cloudwego/hertz-examples/tree/main/monitoring) :hertz 使用 Prometheus 进行指标监控的示例 ### 多端口服务 + - [multiple_service](https://github.com/cloudwego/hertz-examples/tree/main/multiple_service) :使用 Hertz 启动多端口服务的示例 ### 适配器 + - [adaptor](https://github.com/cloudwego/hertz-examples/tree/main/adaptor) :使用 adaptor 集成基于 `http.Handler` 接口开发的工具, 包含使用 [jade](https://github.com/Joker/jade) 作为模版引擎的示例 ### Sentinel + - [sentinel](https://github.com/cloudwego/hertz-examples/tree/main/sentinel) :sentinel-golang 结合 hertz 使用的示例 ### 反向代理 + - [reverseproxy](https://github.com/cloudwego/hertz-examples/tree/main/reverseproxy) :在 hertz server 中使用反向代理的示例 ### Hlog + - [standard](https://github.com/cloudwego/hertz-examples/tree/main/hlog/standard) :使用 hertz 默认实现的日志的示例 - [custom](https://github.com/cloudwego/hertz-examples/tree/main/hlog/custom) :日志扩展的示例 - [zap](https://github.com/cloudwego/hertz-examples/tree/main/hlog/zap) :在 hertz server 中对接 zap 和 lumberjack 的示例 @@ -124,54 +147,69 @@ Hertz 提供了一系列示例代码旨在帮助用户快速上手 Hertz 并了 - [slog](https://github.com/cloudwego/hertz-examples/tree/main/hlog/slog) :在 hertz server 中对接 slog 和 lumberjack 的示例 ### Opentelemetry + - [opentelemetry](https://github.com/cloudwego/hertz-examples/tree/main/opentelemetry) :使用 obs-opentelemetry 的示例用于对接 opentelemetry ### HTTP Trailer + - [trailer](https://github.com/cloudwego/hertz-examples/tree/main/trailer) :使用 HTTP Trailer 的示例 ## Client ### 发送请求 + - [send_request](https://github.com/cloudwego/hertz-examples/tree/main/client/send_request) :使用 hertz client 发送 http 请求的示例 ### 配置 + - [client_config](https://github.com/cloudwego/hertz-examples/tree/main/client/config) :配置 hertz client 的示例 ### TLS + - [tls](https://github.com/cloudwego/hertz-examples/tree/main/protocol/tls) :hertz client 发送 tls 请求的示例 ### 添加请求内容 + - [add_parameters](https://github.com/cloudwego/hertz-examples/tree/main/client/add_parameters) :使用 hertz client 添加请求参数的示例 ### 上传文件 + - [upload_file](https://github.com/cloudwego/hertz-examples/tree/main/client/upload_file) :使用 hertz client 上传文件的示例 ### 中间件 + - [middleware](https://github.com/cloudwego/hertz-examples/tree/main/client/middleware) :使用 hertz client middleware 的示例 ### 流式读响应 + - [streaming_read](https://github.com/cloudwego/hertz-examples/tree/main/client/streaming_read) :使用 hertz client 流式读响应的示例 ### 正向代理 + - [forward_proxy](https://github.com/cloudwego/hertz-examples/tree/main/client/forward_proxy) :使用 hertz client 配置正向代理的示例 ### HTTP Trailer + - [trailer](https://github.com/cloudwego/hertz-examples/tree/main/trailer) :使用 HTTP Trailer 的示例 ## Hz ### 基于 Thrift 生成服务端代码 + - [thrift](https://github.com/cloudwego/hertz-examples/tree/main/hz/thrift) :使用 hz 与 thrift 生成服务端代码的示例 ### 基于 Protobuf 生成服务端代码 + - [protobuf](https://github.com/cloudwego/hertz-examples/tree/main/hz/protobuf) :使用 hz 与 protobuf 生成服务端代码的示例 ### 客户端代码生成 + - [hz_client](https://github.com/cloudwego/hertz-examples/tree/main/hz/hz_client) :使用 hz 生成客户端代码的示例 ### 自定义模板 + - [template](https://github.com/cloudwego/hertz-examples/tree/main/hz/template) :使用 hz 自定义模版生成服务端代码的示例 ### 接入第三方插件 -- [plugin](https://github.com/cloudwego/hertz-examples/tree/main/hz/plugin) :使用 hz 接入第三方插件的示例 +- [plugin](https://github.com/cloudwego/hertz-examples/tree/main/hz/plugin) :使用 hz 接入第三方插件的示例 diff --git a/content/zh/docs/hertz/tutorials/framework-exten/_index.md b/content/zh/docs/hertz/tutorials/framework-exten/_index.md index 3dc1d6e621..9336ee157b 100644 --- a/content/zh/docs/hertz/tutorials/framework-exten/_index.md +++ b/content/zh/docs/hertz/tutorials/framework-exten/_index.md @@ -2,7 +2,15 @@ title: "框架扩展" linkTitle: "框架扩展" weight: 5 -keywords: ["框架扩展", "日志扩展", "监控扩展", "服务注册与发现扩展", "网络库扩展", "协议扩展", "Response 的 Writer 扩展"] +keywords: + [ + "框架扩展", + "日志扩展", + "监控扩展", + "服务注册与发现扩展", + "网络库扩展", + "协议扩展", + "Response 的 Writer 扩展", + ] description: "Hertz 为用户提供的框架扩展能力。" - --- diff --git a/content/zh/docs/hertz/tutorials/framework-exten/log/_index.md b/content/zh/docs/hertz/tutorials/framework-exten/log/_index.md index a104168299..65dbee98d1 100644 --- a/content/zh/docs/hertz/tutorials/framework-exten/log/_index.md +++ b/content/zh/docs/hertz/tutorials/framework-exten/log/_index.md @@ -5,7 +5,6 @@ date: 2023-04-18 weight: 1 keywords: ["日志扩展"] description: "Hertz 提供对日志的扩展,接口定义在 `pkg/common/hlog` 中。" - --- ## 接口定义 @@ -23,14 +22,13 @@ type FullLogger interface { } ``` ->注意,由于默认 logger 底层使用标准库的 `log.Logger` 实现,其在日志里输出的调用位置依赖于设置的调用深度(call depth),因此封装 hlog 提供的实现可能会导致日志内容里文件名和行数不准确。 +> 注意,由于默认 logger 底层使用标准库的 `log.Logger` 实现,其在日志里输出的调用位置依赖于设置的调用深度(call depth),因此封装 hlog 提供的实现可能会导致日志内容里文件名和行数不准确。 ## 注入自己的 logger 实现 Hertz 提供 `SetLogger` 接口用于注入用户自定义的 logger 实现,也可以使用 `SetOutput` 接口重定向默认的 logger 输出,随后的中间件以及框架的其他部分可以使用 hlog 中的全局方法来输出日志。 默认使用 hertz 默认实现的 logger。 - ## 已支持日志拓展 目前在 Hertz 的开源版本支持的日志扩展都存放在 [hertz-logger](https://github.com/hertz-contrib/logger) 中,欢迎大家参与项目贡献与维护。 diff --git a/content/zh/docs/hertz/tutorials/framework-exten/log/logrus.md b/content/zh/docs/hertz/tutorials/framework-exten/log/logrus.md index f4b0e8fc4c..f092219e2c 100644 --- a/content/zh/docs/hertz/tutorials/framework-exten/log/logrus.md +++ b/content/zh/docs/hertz/tutorials/framework-exten/log/logrus.md @@ -78,7 +78,7 @@ func main() { 函数签名: ```go -func WithLogger(logger *logrus.Logger) Option +func WithLogger(logger *logrus.Logger) Option ``` 示例代码: @@ -104,7 +104,7 @@ func main() { 函数签名: ```go -func WithHook(hook logrus.Hook) Option +func WithHook(hook logrus.Hook) Option ``` 示例代码: @@ -172,7 +172,7 @@ func main() { return } } - + logger := hertzlogrus.NewLogger() // 提供压缩和删除 lumberjackLogger := &lumberjack.Logger{ diff --git a/content/zh/docs/hertz/tutorials/framework-exten/log/slog.md b/content/zh/docs/hertz/tutorials/framework-exten/log/slog.md index 0c13050e02..0acd38cb31 100644 --- a/content/zh/docs/hertz/tutorials/framework-exten/log/slog.md +++ b/content/zh/docs/hertz/tutorials/framework-exten/log/slog.md @@ -4,7 +4,6 @@ linkTitle: "slog" weight: 5 keywords: ["日志扩展", "slog"] description: "Hertz 对接 slog 和 lumberjack。" - --- ## Logger 结构体 @@ -107,7 +106,7 @@ func main() { `WithLevel` 对传入的 `*slog.LevelVar` 进行判断,高于或等于这个日志级别的才会被记录 ->值得注意的是,如果 `WithLevel` 与 `WithHandlerOptions` 一起设置,WithLevel 的日志等级会覆盖掉 WithHandlerOptions 中的日志等级 +> 值得注意的是,如果 `WithLevel` 与 `WithHandlerOptions` 一起设置,WithLevel 的日志等级会覆盖掉 WithHandlerOptions 中的日志等级 函数签名: @@ -131,7 +130,7 @@ func main() { // 动态设置日志登记为 LevelDebug levelVar := slog.LevelVar{} levelVar.Set(slog.LevelDebug) - logger := hertzslog.NewLogger(hertzslog.WithLevel(&slog.LevelVar{})) + logger := hertzslog.NewLogger(hertzslog.WithLevel(&slog.LevelVar{})) } ``` @@ -143,7 +142,7 @@ func main() { 函数名称: ```go -func WithHandlerOptions(opts *slog.HandlerOptions) Option +func WithHandlerOptions(opts *slog.HandlerOptions) Option ``` 示例代码: @@ -205,7 +204,7 @@ func main() { return } } - + logger := hertzslog.NewLogger() // 提供压缩和删除 lumberjackLogger := &lumberjack.Logger{ diff --git a/content/zh/docs/hertz/tutorials/framework-exten/log/zap.md b/content/zh/docs/hertz/tutorials/framework-exten/log/zap.md index b0458e7179..69d414d565 100644 --- a/content/zh/docs/hertz/tutorials/framework-exten/log/zap.md +++ b/content/zh/docs/hertz/tutorials/framework-exten/log/zap.md @@ -4,7 +4,6 @@ linkTitle: "zap" weight: 3 keywords: ["日志扩展", "zap"] description: "Hertz 对接 zap 和 lumberjack。" - --- ## Logger 结构体 @@ -144,7 +143,7 @@ func main() { 函数名称: ```go -func WithCoreLevel(lvl zap.AtomicLevel) Option +func WithCoreLevel(lvl zap.AtomicLevel) Option ``` 示例代码: @@ -207,7 +206,7 @@ func main() { 函数签名: ```go -func WithZapOptions(opts ...zap.Option) Option +func WithZapOptions(opts ...zap.Option) Option ``` 示例代码: @@ -321,7 +320,7 @@ func main() { return } } - + logger := hertzzap.NewLogger() // 提供压缩和删除 lumberjackLogger := &lumberjack.Logger{ diff --git a/content/zh/docs/hertz/tutorials/framework-exten/log/zerolog.md b/content/zh/docs/hertz/tutorials/framework-exten/log/zerolog.md index 22244f3d4c..070af7422b 100644 --- a/content/zh/docs/hertz/tutorials/framework-exten/log/zerolog.md +++ b/content/zh/docs/hertz/tutorials/framework-exten/log/zerolog.md @@ -4,7 +4,6 @@ linkTitle: "zerolog" weight: 4 keywords: ["日志扩展", "zerolog"] description: "Hertz 对接 zerolog 和 lumberjack。" - --- ## Logger 结构体 @@ -142,7 +141,7 @@ func main() { 函数签名: ```go -func WithOutput(out io.Writer) Opt +func WithOutput(out io.Writer) Opt ``` 示例代码: @@ -169,7 +168,7 @@ func main() { 函数签名: ```go -func WithLevel(level hlog.Level) Opt +func WithLevel(level hlog.Level) Opt ``` 示例代码: @@ -196,7 +195,7 @@ func main() { 函数签名: ```go -func WithField(name string, value interface{}) Opt +func WithField(name string, value interface{}) Opt ``` 示例代码: @@ -236,7 +235,7 @@ func main() { 函数签名: ```go -func WithFields(fields map[string]interface{}) Opt +func WithFields(fields map[string]interface{}) Opt ``` 示例代码: @@ -265,7 +264,7 @@ func main() { 函数签名: ```go -func WithTimestamp() Opt +func WithTimestamp() Opt ``` 示例代码: @@ -290,7 +289,7 @@ func main() { 函数签名: ```go -func WithFormattedTimestamp(format string) Opt +func WithFormattedTimestamp(format string) Opt ``` 示例代码: @@ -316,7 +315,7 @@ func main() { 函数签名: ```go -func WithCaller() Opt +func WithCaller() Opt ``` 示例代码: @@ -366,7 +365,7 @@ func main() { 函数签名: ```go -func WithCallerSkipFrameCount(skipFrameCount int) Opt +func WithCallerSkipFrameCount(skipFrameCount int) Opt ``` 示例代码: @@ -390,7 +389,7 @@ func main() { 函数签名: ```go -func WithHook(hook zerolog.Hook) Opt +func WithHook(hook zerolog.Hook) Opt ``` 示例代码: diff --git a/content/zh/docs/hertz/tutorials/framework-exten/monitor.md b/content/zh/docs/hertz/tutorials/framework-exten/monitor.md index c130fcfa12..4ffb557d28 100644 --- a/content/zh/docs/hertz/tutorials/framework-exten/monitor.md +++ b/content/zh/docs/hertz/tutorials/framework-exten/monitor.md @@ -4,7 +4,6 @@ linkTitle: "监控扩展" weight: 1 keywords: ["监控扩展"] description: "Hertz 提供的监控扩展。" - --- 用户如果需要更详细的打点,例如包大小,或者想要更换其他数据源,例如 influxDB,用户可以根据自己的需求实现 `Tracer` 接口,并通过 `WithTracer` Option 来注入。 diff --git a/content/zh/docs/hertz/tutorials/framework-exten/network-lib.md b/content/zh/docs/hertz/tutorials/framework-exten/network-lib.md index 4b14fe38a5..ba6ccd6158 100644 --- a/content/zh/docs/hertz/tutorials/framework-exten/network-lib.md +++ b/content/zh/docs/hertz/tutorials/framework-exten/network-lib.md @@ -4,7 +4,6 @@ linkTitle: "网络库扩展" weight: 4 keywords: ["网络库扩展", "network.Conn", "network.StreamConn", "network.Dialer"] description: "Hertz 提供的网络库扩展。" - --- Hertz 提供了网络库扩展的能力。用户如果需要更换其他的网络库,可以根据需求实现对应的接口。Server 需要实现 `network.Conn` 或 `network.StreamConn` 接口,Client 需要实现 `network.Dialer` 接口。 @@ -124,13 +123,13 @@ type Stream interface { type ReceiveStream interface { StreamID() int64 io.Reader - + // CancelRead aborts receiving on this stream. // It will ask the peer to stop transmitting stream data. // Read will unblock immediately, and future Read calls will fail. // When called multiple times or after reading the io.EOF it is a no-op. CancelRead(err ApplicationError) - + // SetReadDeadline sets the deadline for future Read calls and // any currently-blocked Read call. // A zero value for t means Read will not time out. @@ -157,7 +156,7 @@ type SendStream interface { // It must not be called concurrently with Write. // It must not be called after calling CancelWrite. io.Closer - + // The Context is canceled as soon as the write-side of the stream is closed. // This happens when Close() or CancelWrite() is called, or when the peer // cancels the read-side of their stream. diff --git a/content/zh/docs/hertz/tutorials/framework-exten/response_writer.md b/content/zh/docs/hertz/tutorials/framework-exten/response_writer.md index 53759bd82d..96dcd619bf 100644 --- a/content/zh/docs/hertz/tutorials/framework-exten/response_writer.md +++ b/content/zh/docs/hertz/tutorials/framework-exten/response_writer.md @@ -5,7 +5,6 @@ date: 2023-09-22 weight: 6 keywords: ["Response 的 Writer 扩展", "Response.HijackWriter"] description: "Hertz 提供的 Response 的 Writer 扩展。" - --- 按照 Hertz 的 [分层架构](/zh/docs/hertz/overview/) 设计,HTTP 响应实际的写操作是在应用层用户处理逻辑返回之后进行的。用户在这个限制下是不能够灵活按需控制写操作的行为的,这个限制在类似控制 chunk 分块编码写逻辑、[SSE](https://github.com/hertz-contrib/sse#hertz-sse) 的场景下尤为明显。 diff --git a/content/zh/docs/hertz/tutorials/observability/_index.md b/content/zh/docs/hertz/tutorials/observability/_index.md index 3688d2ae0b..aed8d72659 100644 --- a/content/zh/docs/hertz/tutorials/observability/_index.md +++ b/content/zh/docs/hertz/tutorials/observability/_index.md @@ -4,5 +4,4 @@ linkTitle: "可观测性" weight: 3 keywords: ["可观测性", "日志", "链路追踪", "监控", "OpenTelemetry"] description: "Hertz 提供的可观测性能力。" - --- diff --git a/content/zh/docs/hertz/tutorials/observability/log.md b/content/zh/docs/hertz/tutorials/observability/log.md index a6a7b1ce43..f3d27bdefd 100644 --- a/content/zh/docs/hertz/tutorials/observability/log.md +++ b/content/zh/docs/hertz/tutorials/observability/log.md @@ -4,7 +4,6 @@ date: 2022-05-23 weight: 1 keywords: ["日志", "logLevel"] description: "Hertz 提供的日志能力。" - --- Hertz 提供打印日志的方式,默认打在标准输出。实现在 `pkg/common/hlog` 中,Hertz 同时也提供了若干全局函数,例如 `hlog.Info`、`hlog.Errorf`、`hlog.CtxTracef` 等,用于调用默认 logger 的相应方法。 diff --git a/content/zh/docs/hertz/tutorials/observability/monitoring.md b/content/zh/docs/hertz/tutorials/observability/monitoring.md index 312b6c2fc0..e1cef1993e 100644 --- a/content/zh/docs/hertz/tutorials/observability/monitoring.md +++ b/content/zh/docs/hertz/tutorials/observability/monitoring.md @@ -4,7 +4,6 @@ linkTitle: "监控" weight: 4 keywords: ["监控"] description: "Hertz 提供的监控能力。" - --- 框架自身不带任何监控打点,只是提供了 `Tracer` 接口,用户可以根据需求实现该接口,并通过 `WithTracer` Option 来注入。 diff --git a/content/zh/docs/hertz/tutorials/service-governance/_index.md b/content/zh/docs/hertz/tutorials/service-governance/_index.md index 70cd301962..1ba6fe67d8 100644 --- a/content/zh/docs/hertz/tutorials/service-governance/_index.md +++ b/content/zh/docs/hertz/tutorials/service-governance/_index.md @@ -4,5 +4,4 @@ linkTitle: "治理特性" weight: 4 keywords: ["治理特性", "服务注册与发现", "Sentinel"] description: "Hertz 提供的治理特性。" - --- diff --git a/content/zh/docs/hertz/tutorials/service-governance/service_discovery/_index.md b/content/zh/docs/hertz/tutorials/service-governance/service_discovery/_index.md index 5864decbae..7036dd4b69 100644 --- a/content/zh/docs/hertz/tutorials/service-governance/service_discovery/_index.md +++ b/content/zh/docs/hertz/tutorials/service-governance/service_discovery/_index.md @@ -2,7 +2,18 @@ title: "服务注册与发现" date: 2023-04-22 weight: 1 -keywords: ["服务注册与发现", "nacos", "consul", "etcd", "eureka", "polaris", "servicecomb", "zookeeper", "redis"] +keywords: + [ + "服务注册与发现", + "nacos", + "consul", + "etcd", + "eureka", + "polaris", + "servicecomb", + "zookeeper", + "redis", + ] description: "Hertz 提供的服务注册与发现拓展。" --- @@ -23,12 +34,12 @@ description: "Hertz 提供的服务注册与发现拓展。" 使用服务发现时会提供一些可选配置给用户。 -| 配置 | 描述 | -| ---------------------- | ------------------------------------------ | +| 配置 | 描述 | +| ---------------------- | -------------------------------------------------------- | | WithSD | 配合服务发现使用,传递 `true` 时,本次请求使用服务发现。 | -| WithTag | 配合服务发现使用,设置 Tag 信息。 | -| WithCustomizedAddrs | 自定义目标实例地址。 | -| WithLoadBalanceOptions | 配置负载均衡选项。 | +| WithTag | 配合服务发现使用,设置 Tag 信息。 | +| WithCustomizedAddrs | 自定义目标实例地址。 | +| WithLoadBalanceOptions | 配置负载均衡选项。 | ### WithSD @@ -80,7 +91,7 @@ cli.Use(sd.Discovery(r, sd.WithCustomizedAddrs("127.0.0.1:8088"))) ### WithLoadBalanceOptions -`WithLoadBalanceOptions`为客户端配置负载均衡实现和负载均衡参数。可以通过传递`loadbalance.Options`配置负载均衡参数,或者通过传递`loadbalance.DefaultOpts`使用默认负载均衡参数。若不使用此配置项,则客户端默认使用 WeightedRandom 负载均衡实现并且使用默认负载均衡参数。 +`WithLoadBalanceOptions`为客户端配置负载均衡实现和负载均衡参数。可以通过传递`loadbalance.Options`配置负载均衡参数,或者通过传递`loadbalance.DefaultOpts`使用默认负载均衡参数。若不使用此配置项,则客户端默认使用 WeightedRandom 负载均衡实现并且使用默认负载均衡参数。 可以设置的负载均衡参数: @@ -92,7 +103,7 @@ cli.Use(sd.Discovery(r, sd.WithCustomizedAddrs("127.0.0.1:8088"))) 函数签名: ```go -func WithLoadBalanceOptions(lb loadbalance.Loadbalancer, options loadbalance.Options) ServiceDiscoveryOption +func WithLoadBalanceOptions(lb loadbalance.Loadbalancer, options loadbalance.Options) ServiceDiscoveryOption ``` 示例代码: @@ -103,4 +114,5 @@ cli.Use(sd.Discovery(r, sd.WithLoadBalanceOptions(loadbalance.NewWeightedBalance ExpireInterval: 15 * time.Second, }))) ``` + 自定义负载均衡扩展详见[负载均衡扩展](/zh/docs/hertz/tutorials/framework-exten/service_discovery/#负载均衡扩展)。 diff --git a/content/zh/docs/hertz/tutorials/service-governance/service_discovery/consul.md b/content/zh/docs/hertz/tutorials/service-governance/service_discovery/consul.md index e38d9266ed..a5ba144846 100644 --- a/content/zh/docs/hertz/tutorials/service-governance/service_discovery/consul.md +++ b/content/zh/docs/hertz/tutorials/service-governance/service_discovery/consul.md @@ -1,206 +1,206 @@ ---- -title: "consul" -date: 2023-04-22 -weight: 3 -keywords: ["服务注册与发现", "consul"] -description: "Hertz 提供的服务注册与发现 consul 拓展。" ---- - -## 安装 - -```go -go get github.com/hertz-contrib/registry/consul -``` - -## 服务注册 - -### Option - -Consul 拓展在服务注册部分中提供了 option 配置。 - -#### WithCheck - -Consul 扩展提供了 `WithCheck` 用于帮助用户配置 Consul 中的 `AgentServiceCheck` 选项。若不使用,则默认设置 `check.Timeout` 为 5 秒,`check.Internal` 为 5 秒,`check.DeregisterCriticalServiceAfter` 为 1 分钟。 - -函数签名: - -```go -func WithCheck(check *api.AgentServiceCheck) Option -``` - -示例代码: - -```go -func main() { - // ... - consulClient, err := consulapi.NewClient(config) - // ... - check := &consulapi.AgentServiceCheck{ - // ... - } - r := consul.NewConsulRegister(consulClient, consul.WithCheck(check)) - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -### NewConsulRegister - -`NewConsulRegister` 使用 consul 创建一个可配置客户端的服务注册中心,需要传入客户端,其中客户端使用 `NewClient` 创建。可自定义服务注册中心配置。 - -函数签名: - -```go -func NewConsulRegister(consulClient *api.Client, opts ...Option) registry.Registry -``` - -示例代码: - -```go -func main() { - // ... - consulClient, err := consulapi.NewClient(config) - // ... - r := consul.NewConsulRegister(consulClient) - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -## 服务发现 - -### NewConsulResolver - -`NewConsulResolver` 使用 consul 创建一个新的服务发现中心,需要传入客户端,其中客户端使用 `NewClient` 创建。可自定义服务发现中心配置。 - -函数签名: - -```go -func NewConsulResolver(consulClient *api.Client) discovery.Resolver -``` - -示例代码: - -```go -func main() { - // ... - consulClient, err := consulapi.NewClient(consulConfig) - if err != nil { - log.Fatal(err) - return - } - r := consul.NewConsulResolver(consulClient) - - cli, err := client.NewClient() - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) -} -``` - -## 使用示例 - -### 服务端 - -```go -import ( - "context" - "log" - - "github.com/cloudwego/hertz/pkg/app" - "github.com/cloudwego/hertz/pkg/app/server" - "github.com/cloudwego/hertz/pkg/app/server/registry" - "github.com/cloudwego/hertz/pkg/common/utils" - "github.com/cloudwego/hertz/pkg/protocol/consts" - consulapi "github.com/hashicorp/consul/api" - "github.com/hertz-contrib/registry/consul" -) - - -func main() { - // build a consul client - config := consulapi.DefaultConfig() - config.Address = "127.0.0.1:8500" - consulClient, err := consulapi.NewClient(config) - if err != nil { - log.Fatal(err) - return - } - // build a consul register with the consul client - r := consul.NewConsulRegister(consulClient) - - // run Hertz with the consul register - addr := "127.0.0.1:8888" - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { - ctx.JSON(consts.StatusOK, utils.H{"ping": "pong1"}) - }) - h.Spin() -} -``` - -### 客户端 - -```go -import ( - "log" - - "github.com/cloudwego/hertz/pkg/app/client" - "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" - consulapi "github.com/hashicorp/consul/api" - "github.com/hertz-contrib/registry/consul" -) - -func main() { - // build a consul client - consulConfig := consulapi.DefaultConfig() - consulConfig.Address = "127.0.0.1:8500" - consulClient, err := consulapi.NewClient(consulConfig) - if err != nil { - log.Fatal(err) - return - } - // build a consul resolver with the consul client - r := consul.NewConsulResolver(consulClient) - - // build a hertz client with the consul resolver - cli, err := client.NewClient() - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) -} -``` - -## 配置 - -可自定义 Consul 客户端以及服务端的配置,参考 [consul](https://github.com/hashicorp/consul) 配置。 - -## 完整实例 - -完整用法示例详见 [example](https://github.com/hertz-contrib/registry/tree/main/consul/example) 。 +--- +title: "consul" +date: 2023-04-22 +weight: 3 +keywords: ["服务注册与发现", "consul"] +description: "Hertz 提供的服务注册与发现 consul 拓展。" +--- + +## 安装 + +```go +go get github.com/hertz-contrib/registry/consul +``` + +## 服务注册 + +### Option + +Consul 拓展在服务注册部分中提供了 option 配置。 + +#### WithCheck + +Consul 扩展提供了 `WithCheck` 用于帮助用户配置 Consul 中的 `AgentServiceCheck` 选项。若不使用,则默认设置 `check.Timeout` 为 5 秒,`check.Internal` 为 5 秒,`check.DeregisterCriticalServiceAfter` 为 1 分钟。 + +函数签名: + +```go +func WithCheck(check *api.AgentServiceCheck) Option +``` + +示例代码: + +```go +func main() { + // ... + consulClient, err := consulapi.NewClient(config) + // ... + check := &consulapi.AgentServiceCheck{ + // ... + } + r := consul.NewConsulRegister(consulClient, consul.WithCheck(check)) + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +### NewConsulRegister + +`NewConsulRegister` 使用 consul 创建一个可配置客户端的服务注册中心,需要传入客户端,其中客户端使用 `NewClient` 创建。可自定义服务注册中心配置。 + +函数签名: + +```go +func NewConsulRegister(consulClient *api.Client, opts ...Option) registry.Registry +``` + +示例代码: + +```go +func main() { + // ... + consulClient, err := consulapi.NewClient(config) + // ... + r := consul.NewConsulRegister(consulClient) + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +## 服务发现 + +### NewConsulResolver + +`NewConsulResolver` 使用 consul 创建一个新的服务发现中心,需要传入客户端,其中客户端使用 `NewClient` 创建。可自定义服务发现中心配置。 + +函数签名: + +```go +func NewConsulResolver(consulClient *api.Client) discovery.Resolver +``` + +示例代码: + +```go +func main() { + // ... + consulClient, err := consulapi.NewClient(consulConfig) + if err != nil { + log.Fatal(err) + return + } + r := consul.NewConsulResolver(consulClient) + + cli, err := client.NewClient() + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) +} +``` + +## 使用示例 + +### 服务端 + +```go +import ( + "context" + "log" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/protocol/consts" + consulapi "github.com/hashicorp/consul/api" + "github.com/hertz-contrib/registry/consul" +) + + +func main() { + // build a consul client + config := consulapi.DefaultConfig() + config.Address = "127.0.0.1:8500" + consulClient, err := consulapi.NewClient(config) + if err != nil { + log.Fatal(err) + return + } + // build a consul register with the consul client + r := consul.NewConsulRegister(consulClient) + + // run Hertz with the consul register + addr := "127.0.0.1:8888" + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { + ctx.JSON(consts.StatusOK, utils.H{"ping": "pong1"}) + }) + h.Spin() +} +``` + +### 客户端 + +```go +import ( + "log" + + "github.com/cloudwego/hertz/pkg/app/client" + "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" + consulapi "github.com/hashicorp/consul/api" + "github.com/hertz-contrib/registry/consul" +) + +func main() { + // build a consul client + consulConfig := consulapi.DefaultConfig() + consulConfig.Address = "127.0.0.1:8500" + consulClient, err := consulapi.NewClient(consulConfig) + if err != nil { + log.Fatal(err) + return + } + // build a consul resolver with the consul client + r := consul.NewConsulResolver(consulClient) + + // build a hertz client with the consul resolver + cli, err := client.NewClient() + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) +} +``` + +## 配置 + +可自定义 Consul 客户端以及服务端的配置,参考 [consul](https://github.com/hashicorp/consul) 配置。 + +## 完整实例 + +完整用法示例详见 [example](https://github.com/hertz-contrib/registry/tree/main/consul/example) 。 diff --git a/content/zh/docs/hertz/tutorials/service-governance/service_discovery/etcd.md b/content/zh/docs/hertz/tutorials/service-governance/service_discovery/etcd.md index ad076f9853..05f30ecb36 100644 --- a/content/zh/docs/hertz/tutorials/service-governance/service_discovery/etcd.md +++ b/content/zh/docs/hertz/tutorials/service-governance/service_discovery/etcd.md @@ -1,396 +1,396 @@ ---- -title: "etcd" -date: 2023-10-18 -weight: 4 -keywords: ["服务注册与发现", "etcd"] -description: "Hertz 提供的服务注册与发现 etcd 拓展。" ---- - -## 安装 - -```go -go get github.com/hertz-contrib/registry/etcd -``` - -## 服务注册 - -### Option - -Etcd 拓展在服务注册部分中提供了 option 配置。 - -#### WithTLSOpt - -Etcd 扩展提供了 `WithTLSOpt` 用于帮助用户配置 Etcd 中的 `TLS` 选项。 - -函数签名: - -```go -func WithTLSOpt(certFile, keyFile, caFile string) Option -``` - -示例代码: - -```go -func main() { - r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}, - etcd.WithTLSOpt(certFile, keyFile, caFile), - ) - if err != nil { - panic(err) - } - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - // ... -} -``` - -#### WithAuthOpt - -Etcd 扩展提供了 `WithAuthOpt` 用于帮助用户配置 Etcd 中的 `Username` 和 `Password` 选项。 - -函数签名: - -```go -func WithAuthOpt(username, password string) Option -``` - -示例代码: - -```go -func main() { - r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}, - etcd.WithAuthOpt("root","123456"), - ) - if err != nil { - panic(err) - } - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - // ... -} -``` - -#### Retry - -在服务注册到 etcd 之后,它会定期检查服务的状态。如果发现任何异常状态,它将尝试重新注册服务。observeDelay 是正常情况下检查服务状态的延迟时间,而 retryDelay 是断开连接后尝试注册服务的延迟时间。 - -**默认配置** - -| 配置名 | 默认值 | 描述 | -| ------------------- | ---------------- | --------------------------------------------- | -| WithMaxAttemptTimes | 5 | 用于设置最大尝试次数,如果为 0,则表示无限尝试 | -| WithObserveDelay | 30 * time.Second | 用于设置正常连接条件下检查服务状态的延迟时间 | -| WithRetryDelay | 10 * time.Second | 用于设置断开连接后重试的延迟时间 | - -##### WithMaxAttemptTimes - -`WithMaxAttemptTimes` 用于设置最大尝试次数,包括初始调用。 - -函数签名: - -```go -func WithMaxAttemptTimes(maxAttemptTimes uint) Option -``` - -示例代码: - -```go -func main() { - r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}, - etcd.WithMaxAttemptTimes(10), - ) - if err != nil { - panic(err) - } - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - // ... -} -``` - -##### WithObserveDelay - -`WithObserveDelay` 用于设置正常连接条件下检查服务状态的延迟时间。 - -函数签名: - -```go -func WithObserveDelay(observeDelay time.Duration) Option -``` - -示例代码: - -```go -func main() { - r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}, - etcd.WithObserveDelay(20*time.Second), - ) - if err != nil { - panic(err) - } - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - // ... -} -``` - -##### WithRetryDelay - -`WithRetryDelay` 用于设置断开连接后重试的延迟时间。 - -函数签名: - -```go -func WithRetryDelay(t time.Duration) Option -``` - -示例代码: - -```go -func main() { - r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}, - etcd.WithRetryDelay(5*time.Second), - ) - if err != nil { - panic(err) - } - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - // ... -} -``` - -### NewEtcdRegistry - -`NewEtcdRegistry` 使用 etcd 创建一个新的服务注册中心,需要传入端点值。可自定义服务注册中心配置。 - -函数签名: - -```go -func NewEtcdRegistry(endpoints []string, opts ...Option) (registry.Registry, error) -``` - -示例代码: - -```go -func main() { - r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}) - if err != nil { - panic(err) - } - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - // ... -} -``` - -## 服务发现 - -### Option - -Etcd 拓展在服务发现部分中提供了 option 配置。 - -#### WithTLSOpt - -Etcd 扩展提供了 `WithTLSOpt` 用于帮助用户配置 Etcd 中的 `TLS` 选项。 - -函数签名: - -```go -func WithTLSOpt(certFile, keyFile, caFile string) Option -``` - -示例代码: - -```go -func main() { - cli, err := client.NewClient() - if err != nil { - panic(err) - } - r, err := etcd.NewEtcdResolver([]string{"127.0.0.1:2379"}, - etcd.WithTLSOpt(certFile, keyFile, caFile), - ) - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - // ... -} -``` - -#### WithAuthOpt - -Etcd 扩展提供了 `WithAuthOpt` 用于帮助用户配置 Etcd 中的 `Username` 和 `Password` 选项。 - -函数签名: - -```go -func WithAuthOpt(username, password string) Option -``` - -示例代码: - -``` -func main() { - cli, err := client.NewClient() - if err != nil { - panic(err) - } - r, err := etcd.NewEtcdResolver([]string{"127.0.0.1:2379"}, - etcd.WithAuthOpt("root","123456"), - ) - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - // ... -} -``` - -### NewEtcdResolver - -`NewEtcdResolver` 使用 etcd 创建一个新的服务发现中心,需要传入端点值。可自定义服务发现中心配置。 - -函数签名: - -```go -func NewEtcdResolver(endpoints []string, opts ...Option) (discovery.Resolver, error) -``` - -示例代码: - -```go -func main() { - cli, err := client.NewClient() - if err != nil { - panic(err) - } - r, err := etcd.NewEtcdResolver([]string{"127.0.0.1:2379"}) - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - // ... -} -``` - -## 使用示例 - -### 服务端 - -```go -import ( - "context" - - "github.com/cloudwego/hertz/pkg/app" - "github.com/cloudwego/hertz/pkg/app/server" - "github.com/cloudwego/hertz/pkg/app/server/registry" - "github.com/cloudwego/hertz/pkg/common/utils" - "github.com/cloudwego/hertz/pkg/protocol/consts" - "github.com/hertz-contrib/registry/etcd" -) - -func main() { - r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}) - if err != nil { - panic(err) - } - addr := "127.0.0.1:8888" - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - h.GET("/ping", func(_ context.Context, ctx *app.RequestContext) { - ctx.JSON(consts.StatusOK, utils.H{"ping": "pong2"}) - }) - h.Spin() -} -``` - -### 客户端 - -```go -import ( - "context" - - "github.com/cloudwego/hertz/pkg/app/client" - "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" - "github.com/cloudwego/hertz/pkg/common/config" - "github.com/cloudwego/hertz/pkg/common/hlog" - "github.com/hertz-contrib/registry/etcd" -) - -func main() { - cli, err := client.NewClient() - if err != nil { - panic(err) - } - r, err := etcd.NewEtcdResolver([]string{"127.0.0.1:2379"}) - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - for i := 0; i < 10; i++ { - status, body, err := cli.Get(context.Background(), nil, "http://hertz.test.demo/ping", config.WithSD(true)) - if err != nil { - hlog.Fatal(err) - } - hlog.Infof("HERTZ: code=%d,body=%s", status, string(body)) - } -} -``` - -## 配置 - -可自定义 Etcd 客户端以及服务端的配置,参考 [etcd-client](https://pkg.go.dev/go.etcd.io/etcd/client/v3) 配置。 - -## 完整示例 - -完整用法示例详见 [example](https://github.com/hertz-contrib/registry/tree/main/etcd/example) 。 +--- +title: "etcd" +date: 2023-10-18 +weight: 4 +keywords: ["服务注册与发现", "etcd"] +description: "Hertz 提供的服务注册与发现 etcd 拓展。" +--- + +## 安装 + +```go +go get github.com/hertz-contrib/registry/etcd +``` + +## 服务注册 + +### Option + +Etcd 拓展在服务注册部分中提供了 option 配置。 + +#### WithTLSOpt + +Etcd 扩展提供了 `WithTLSOpt` 用于帮助用户配置 Etcd 中的 `TLS` 选项。 + +函数签名: + +```go +func WithTLSOpt(certFile, keyFile, caFile string) Option +``` + +示例代码: + +```go +func main() { + r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}, + etcd.WithTLSOpt(certFile, keyFile, caFile), + ) + if err != nil { + panic(err) + } + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + // ... +} +``` + +#### WithAuthOpt + +Etcd 扩展提供了 `WithAuthOpt` 用于帮助用户配置 Etcd 中的 `Username` 和 `Password` 选项。 + +函数签名: + +```go +func WithAuthOpt(username, password string) Option +``` + +示例代码: + +```go +func main() { + r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}, + etcd.WithAuthOpt("root","123456"), + ) + if err != nil { + panic(err) + } + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + // ... +} +``` + +#### Retry + +在服务注册到 etcd 之后,它会定期检查服务的状态。如果发现任何异常状态,它将尝试重新注册服务。observeDelay 是正常情况下检查服务状态的延迟时间,而 retryDelay 是断开连接后尝试注册服务的延迟时间。 + +**默认配置** + +| 配置名 | 默认值 | 描述 | +| ------------------- | ----------------- | ---------------------------------------------- | +| WithMaxAttemptTimes | 5 | 用于设置最大尝试次数,如果为 0,则表示无限尝试 | +| WithObserveDelay | 30 \* time.Second | 用于设置正常连接条件下检查服务状态的延迟时间 | +| WithRetryDelay | 10 \* time.Second | 用于设置断开连接后重试的延迟时间 | + +##### WithMaxAttemptTimes + +`WithMaxAttemptTimes` 用于设置最大尝试次数,包括初始调用。 + +函数签名: + +```go +func WithMaxAttemptTimes(maxAttemptTimes uint) Option +``` + +示例代码: + +```go +func main() { + r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}, + etcd.WithMaxAttemptTimes(10), + ) + if err != nil { + panic(err) + } + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + // ... +} +``` + +##### WithObserveDelay + +`WithObserveDelay` 用于设置正常连接条件下检查服务状态的延迟时间。 + +函数签名: + +```go +func WithObserveDelay(observeDelay time.Duration) Option +``` + +示例代码: + +```go +func main() { + r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}, + etcd.WithObserveDelay(20*time.Second), + ) + if err != nil { + panic(err) + } + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + // ... +} +``` + +##### WithRetryDelay + +`WithRetryDelay` 用于设置断开连接后重试的延迟时间。 + +函数签名: + +```go +func WithRetryDelay(t time.Duration) Option +``` + +示例代码: + +```go +func main() { + r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}, + etcd.WithRetryDelay(5*time.Second), + ) + if err != nil { + panic(err) + } + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + // ... +} +``` + +### NewEtcdRegistry + +`NewEtcdRegistry` 使用 etcd 创建一个新的服务注册中心,需要传入端点值。可自定义服务注册中心配置。 + +函数签名: + +```go +func NewEtcdRegistry(endpoints []string, opts ...Option) (registry.Registry, error) +``` + +示例代码: + +```go +func main() { + r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}) + if err != nil { + panic(err) + } + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + // ... +} +``` + +## 服务发现 + +### Option + +Etcd 拓展在服务发现部分中提供了 option 配置。 + +#### WithTLSOpt + +Etcd 扩展提供了 `WithTLSOpt` 用于帮助用户配置 Etcd 中的 `TLS` 选项。 + +函数签名: + +```go +func WithTLSOpt(certFile, keyFile, caFile string) Option +``` + +示例代码: + +```go +func main() { + cli, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := etcd.NewEtcdResolver([]string{"127.0.0.1:2379"}, + etcd.WithTLSOpt(certFile, keyFile, caFile), + ) + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + // ... +} +``` + +#### WithAuthOpt + +Etcd 扩展提供了 `WithAuthOpt` 用于帮助用户配置 Etcd 中的 `Username` 和 `Password` 选项。 + +函数签名: + +```go +func WithAuthOpt(username, password string) Option +``` + +示例代码: + +``` +func main() { + cli, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := etcd.NewEtcdResolver([]string{"127.0.0.1:2379"}, + etcd.WithAuthOpt("root","123456"), + ) + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + // ... +} +``` + +### NewEtcdResolver + +`NewEtcdResolver` 使用 etcd 创建一个新的服务发现中心,需要传入端点值。可自定义服务发现中心配置。 + +函数签名: + +```go +func NewEtcdResolver(endpoints []string, opts ...Option) (discovery.Resolver, error) +``` + +示例代码: + +```go +func main() { + cli, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := etcd.NewEtcdResolver([]string{"127.0.0.1:2379"}) + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + // ... +} +``` + +## 使用示例 + +### 服务端 + +```go +import ( + "context" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/protocol/consts" + "github.com/hertz-contrib/registry/etcd" +) + +func main() { + r, err := etcd.NewEtcdRegistry([]string{"127.0.0.1:2379"}) + if err != nil { + panic(err) + } + addr := "127.0.0.1:8888" + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + h.GET("/ping", func(_ context.Context, ctx *app.RequestContext) { + ctx.JSON(consts.StatusOK, utils.H{"ping": "pong2"}) + }) + h.Spin() +} +``` + +### 客户端 + +```go +import ( + "context" + + "github.com/cloudwego/hertz/pkg/app/client" + "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" + "github.com/cloudwego/hertz/pkg/common/config" + "github.com/cloudwego/hertz/pkg/common/hlog" + "github.com/hertz-contrib/registry/etcd" +) + +func main() { + cli, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := etcd.NewEtcdResolver([]string{"127.0.0.1:2379"}) + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + for i := 0; i < 10; i++ { + status, body, err := cli.Get(context.Background(), nil, "http://hertz.test.demo/ping", config.WithSD(true)) + if err != nil { + hlog.Fatal(err) + } + hlog.Infof("HERTZ: code=%d,body=%s", status, string(body)) + } +} +``` + +## 配置 + +可自定义 Etcd 客户端以及服务端的配置,参考 [etcd-client](https://pkg.go.dev/go.etcd.io/etcd/client/v3) 配置。 + +## 完整示例 + +完整用法示例详见 [example](https://github.com/hertz-contrib/registry/tree/main/etcd/example) 。 diff --git a/content/zh/docs/hertz/tutorials/service-governance/service_discovery/eureka.md b/content/zh/docs/hertz/tutorials/service-governance/service_discovery/eureka.md index 14b7e37ca9..cb4359d1bf 100644 --- a/content/zh/docs/hertz/tutorials/service-governance/service_discovery/eureka.md +++ b/content/zh/docs/hertz/tutorials/service-governance/service_discovery/eureka.md @@ -1,268 +1,268 @@ ---- -title: "eureka" -date: 2023-04-22 -weight: 5 -keywords: ["服务注册与发现", "eureka"] -description: "Hertz 提供的服务注册与发现 eureka 拓展。" ---- - -## 安装 - -```go -go get github.com/hertz-contrib/eureka -``` - -## 服务注册 - -### NewEurekaRegistry - -`NewEurekaRegistry` 使用 eureka 创建一个新的服务注册中心,需要将服务 Url 通过一个字符串切片传入 `NewConn`,并同时传入心跳间隔时长。 - -函数签名: - -```go -func NewEurekaRegistry(servers []string, heatBeatInterval time.Duration) *eurekaRegistry -``` - -示例代码: - -```go -func main() { - // ... - r := eureka.NewEurekaRegistry([]string{"http://127.0.0.1:8761/eureka"}, 40*time.Second) - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.discovery.eureka", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - //... -} -``` - -### NewEurekaRegistryFromConfig - -`NewEurekaRegistryFromConfig` 使用 eureka 创建一个新的服务注册中心,需要传入配置并调用 `NewConnFromConfig`,也需要传入心跳间隔时长。 - -函数签名: - -```go -func NewEurekaRegistryFromConfig(config fargo.Config, heatBeatInterval time.Duration) *eurekaRegistry -``` - -示例代码: - -```go -func main() { - // ... - config := fargo.Config{ - // ... - } - r := eureka.NewEurekaRegistryFromConfig(config, 40*time.Second) - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.discovery.eureka", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - //... -} -``` - -### NewEurekaRegistryFromConn - -`NewEurekaRegistryFromConn` 使用 eureka 创建一个新的服务注册中心,需要直接传入 conn,也需要传入心跳间隔时长。 - -函数签名: - -```go -func NewEurekaRegistryFromConn(conn fargo.EurekaConnection, heatBeatInterval time.Duration) *eurekaRegistry -``` - -示例代码: - -```go -func main() { - // ... - conn := fargo.EurekaConnection{ - // ... - } - r := eureka.NewEurekaRegistryFromConn(conn, 40*time.Second) - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.discovery.eureka", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - //... -} -``` - -## 服务发现 - -### NewEurekaResolver - -`NewEurekaResolver` 使用 eureka 创建一个新的服务发现中心,需要将服务 Url 通过一个字符串切片传入 `NewConn`。 - -函数签名: - -```go -func NewEurekaResolver(servers []string) *eurekaResolver -``` - -示例代码: - -```go -func main() { - cli, err := client.NewClient() - if err != nil { - hlog.Fatal(err) - return - } - r := eureka.NewEurekaResolver([]string{"http://127.0.0.1:8761/eureka"}) - - cli.Use(sd.Discovery(r)) - // ... -} -``` - -### NewEurekaResolverFromConfig - -`NewEurekaResolverFromConfig` 使用 eureka 创建一个新的服务发现中心,需要传入配置并调用 `NewConnFromConfig`。 - -函数签名: - -```go -func NewEurekaResolverFromConfig(config fargo.Config) *eurekaResolver -``` - -示例代码: - -```go -func main() { - // ... - config := fargo.Config{ - // ... - } - cli, err := client.NewClient() - if err != nil { - hlog.Fatal(err) - return - } - r := eureka.NewEurekaResolverFromConfig(config) - - cli.Use(sd.Discovery(r)) - // ... -} -``` - -### NewEurekaResolverFromConn - -`NewEurekaResolverFromConn` 使用 eureka 创建一个新的服务发现中心,需要直接传入 conn。 - -函数签名: - -```go -func NewEurekaResolverFromConn(conn fargo.EurekaConnection) *eurekaResolver -``` - -示例代码: - -```go -func main() { - // ... - conn := fargo.EurekaConnection{ - // ... - } - cli, err := client.NewClient() - if err != nil { - hlog.Fatal(err) - return - } - r := eureka.NewEurekaResolverFromConn(conn) - - cli.Use(sd.Discovery(r)) - // ... -} -``` - -## 使用示例 - -### 服务端 - -```go -import ( - "context" - "time" - - "github.com/cloudwego/hertz/pkg/app" - "github.com/cloudwego/hertz/pkg/app/server" - "github.com/cloudwego/hertz/pkg/app/server/registry" - "github.com/cloudwego/hertz/pkg/common/utils" - "github.com/cloudwego/hertz/pkg/protocol/consts" - "github.com/hertz-contrib/registry/eureka" -) - -func main() { - addr := "127.0.0.1:8888" - r := eureka.NewEurekaRegistry([]string{"http://127.0.0.1:8761/eureka"}, 40*time.Second) - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.discovery.eureka", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { - ctx.JSON(consts.StatusOK, utils.H{"ping": "pong2"}) - }) - h.Spin() -} -``` - -### 客户端 - -```go -import ( - "context" - - "github.com/cloudwego/hertz/pkg/app/client" - "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" - "github.com/cloudwego/hertz/pkg/common/config" - "github.com/cloudwego/hertz/pkg/common/hlog" - "github.com/hertz-contrib/registry/eureka" -) - -func main() { - cli, err := client.NewClient() - if err != nil { - hlog.Fatal(err) - return - } - r := eureka.NewEurekaResolver([]string{"http://127.0.0.1:8761/eureka"}) - - cli.Use(sd.Discovery(r)) - for i := 0; i < 10; i++ { - status, body, err := cli.Get(context.Background(), nil, "http://hertz.discovery.eureka/ping", config.WithSD(true)) - if err != nil { - hlog.Fatal(err) - } - hlog.Infof("code=%d,body=%s", status, string(body)) - } -} -``` - -## 配置 - -本项目使用 [fargo](https://github.com/hudl/fargo) 作为 eureka 客户端。您应该参考 [fargo](https://github.com/hudl/fargo) 文档以了解高级配置。 - -## 完整示例 - -完整用法示例详见 [example](https://github.com/hertz-contrib/registry/tree/main/eureka/example) 。 +--- +title: "eureka" +date: 2023-04-22 +weight: 5 +keywords: ["服务注册与发现", "eureka"] +description: "Hertz 提供的服务注册与发现 eureka 拓展。" +--- + +## 安装 + +```go +go get github.com/hertz-contrib/eureka +``` + +## 服务注册 + +### NewEurekaRegistry + +`NewEurekaRegistry` 使用 eureka 创建一个新的服务注册中心,需要将服务 Url 通过一个字符串切片传入 `NewConn`,并同时传入心跳间隔时长。 + +函数签名: + +```go +func NewEurekaRegistry(servers []string, heatBeatInterval time.Duration) *eurekaRegistry +``` + +示例代码: + +```go +func main() { + // ... + r := eureka.NewEurekaRegistry([]string{"http://127.0.0.1:8761/eureka"}, 40*time.Second) + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.discovery.eureka", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + //... +} +``` + +### NewEurekaRegistryFromConfig + +`NewEurekaRegistryFromConfig` 使用 eureka 创建一个新的服务注册中心,需要传入配置并调用 `NewConnFromConfig`,也需要传入心跳间隔时长。 + +函数签名: + +```go +func NewEurekaRegistryFromConfig(config fargo.Config, heatBeatInterval time.Duration) *eurekaRegistry +``` + +示例代码: + +```go +func main() { + // ... + config := fargo.Config{ + // ... + } + r := eureka.NewEurekaRegistryFromConfig(config, 40*time.Second) + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.discovery.eureka", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + //... +} +``` + +### NewEurekaRegistryFromConn + +`NewEurekaRegistryFromConn` 使用 eureka 创建一个新的服务注册中心,需要直接传入 conn,也需要传入心跳间隔时长。 + +函数签名: + +```go +func NewEurekaRegistryFromConn(conn fargo.EurekaConnection, heatBeatInterval time.Duration) *eurekaRegistry +``` + +示例代码: + +```go +func main() { + // ... + conn := fargo.EurekaConnection{ + // ... + } + r := eureka.NewEurekaRegistryFromConn(conn, 40*time.Second) + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.discovery.eureka", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + //... +} +``` + +## 服务发现 + +### NewEurekaResolver + +`NewEurekaResolver` 使用 eureka 创建一个新的服务发现中心,需要将服务 Url 通过一个字符串切片传入 `NewConn`。 + +函数签名: + +```go +func NewEurekaResolver(servers []string) *eurekaResolver +``` + +示例代码: + +```go +func main() { + cli, err := client.NewClient() + if err != nil { + hlog.Fatal(err) + return + } + r := eureka.NewEurekaResolver([]string{"http://127.0.0.1:8761/eureka"}) + + cli.Use(sd.Discovery(r)) + // ... +} +``` + +### NewEurekaResolverFromConfig + +`NewEurekaResolverFromConfig` 使用 eureka 创建一个新的服务发现中心,需要传入配置并调用 `NewConnFromConfig`。 + +函数签名: + +```go +func NewEurekaResolverFromConfig(config fargo.Config) *eurekaResolver +``` + +示例代码: + +```go +func main() { + // ... + config := fargo.Config{ + // ... + } + cli, err := client.NewClient() + if err != nil { + hlog.Fatal(err) + return + } + r := eureka.NewEurekaResolverFromConfig(config) + + cli.Use(sd.Discovery(r)) + // ... +} +``` + +### NewEurekaResolverFromConn + +`NewEurekaResolverFromConn` 使用 eureka 创建一个新的服务发现中心,需要直接传入 conn。 + +函数签名: + +```go +func NewEurekaResolverFromConn(conn fargo.EurekaConnection) *eurekaResolver +``` + +示例代码: + +```go +func main() { + // ... + conn := fargo.EurekaConnection{ + // ... + } + cli, err := client.NewClient() + if err != nil { + hlog.Fatal(err) + return + } + r := eureka.NewEurekaResolverFromConn(conn) + + cli.Use(sd.Discovery(r)) + // ... +} +``` + +## 使用示例 + +### 服务端 + +```go +import ( + "context" + "time" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/protocol/consts" + "github.com/hertz-contrib/registry/eureka" +) + +func main() { + addr := "127.0.0.1:8888" + r := eureka.NewEurekaRegistry([]string{"http://127.0.0.1:8761/eureka"}, 40*time.Second) + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.discovery.eureka", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { + ctx.JSON(consts.StatusOK, utils.H{"ping": "pong2"}) + }) + h.Spin() +} +``` + +### 客户端 + +```go +import ( + "context" + + "github.com/cloudwego/hertz/pkg/app/client" + "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" + "github.com/cloudwego/hertz/pkg/common/config" + "github.com/cloudwego/hertz/pkg/common/hlog" + "github.com/hertz-contrib/registry/eureka" +) + +func main() { + cli, err := client.NewClient() + if err != nil { + hlog.Fatal(err) + return + } + r := eureka.NewEurekaResolver([]string{"http://127.0.0.1:8761/eureka"}) + + cli.Use(sd.Discovery(r)) + for i := 0; i < 10; i++ { + status, body, err := cli.Get(context.Background(), nil, "http://hertz.discovery.eureka/ping", config.WithSD(true)) + if err != nil { + hlog.Fatal(err) + } + hlog.Infof("code=%d,body=%s", status, string(body)) + } +} +``` + +## 配置 + +本项目使用 [fargo](https://github.com/hudl/fargo) 作为 eureka 客户端。您应该参考 [fargo](https://github.com/hudl/fargo) 文档以了解高级配置。 + +## 完整示例 + +完整用法示例详见 [example](https://github.com/hertz-contrib/registry/tree/main/eureka/example) 。 diff --git a/content/zh/docs/hertz/tutorials/service-governance/service_discovery/nacos.md b/content/zh/docs/hertz/tutorials/service-governance/service_discovery/nacos.md index eef02b640e..500d537c7f 100644 --- a/content/zh/docs/hertz/tutorials/service-governance/service_discovery/nacos.md +++ b/content/zh/docs/hertz/tutorials/service-governance/service_discovery/nacos.md @@ -1,404 +1,403 @@ ---- -title: "nacos" -date: 2023-04-22 -weight: 2 -keywords: ["服务注册与发现", "nacos"] -description: "Hertz 提供的服务注册与发现 nacos 拓展。" ---- - - -## 安装 - -- nacos-sdk-go v1 版本 - -```go -go get github.com/hertz-contrib/registry/nacos -``` - -- nacos-sdk-go v2 版本 - -```go -go get github.com/hertz-contrib/registry/nacos/v2 -``` - -## 服务注册 - -### Option - -Nacos 拓展在服务注册部分中提供了 option 配置。 - -#### WithRegistryCluster - -Nacos 扩展提供了 `WithRegistryCluster` 用于帮助用户配置自定义的集群。默认为“DEFAULT” 。 - -函数签名: - -```go -func WithRegistryCluster(cluster string) RegistryOption -``` - -示例代码: - -```go -func main() { - // ... - r, err := nacos.NewDefaultNacosRegistry( - nacos.WithRegistryCluster("Cluster123"), - ) - if err != nil { - log.Fatal(err) - return - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -#### WithRegistryGroup - -Nacos 扩展提供了 `WithRegistryGroup` 用于帮助用户配置自定义的集群。默认为 "DEFAULT_GROUP" 。 - -函数签名: - -```go -func WithRegistryGroup(group string) RegistryOption -``` - -示例代码: - -```go -func main() { - // ... - r, err := nacos.NewDefaultNacosRegistry( - nacos.WithRegistryGroup("Group1"), - ) - if err != nil { - log.Fatal(err) - return - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -### NewDefaultNacosRegistry - -`NewDefaultNacosRegistry` 使用 nacos 创建一个默认的服务注册中心。会调用 `NewDefaultNacosConfig` 读取环境变量来创建一个默认的 nacos 客户端,并设置 RegionId 为 `cn-hangzhou`,且不会在启动时自动预加载服务实例信息到本地缓存。可自定义服务注册中心配置。 - -环境变量: - -| 环境变量名 | 环境变量默认值 | 描述 | -| ---------- | -------------- | ----------------------- | -| serverAddr | 127.0.0.1 | nacos 服务器地址 | -| serverPort | 8848 | nacos 服务器端口 | -| namespace | | nacos 中的 namespace Id | - -函数签名: - -```go -func NewDefaultNacosRegistry(opts ...RegistryOption) (registry.Registry, error) -``` - -示例代码: - -```go -func main() { - // ... - r, err := nacos.NewDefaultNacosRegistry() - if err != nil { - log.Fatal(err) - return - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -### NewNacosRegistry - -`NewNacosRegistry` 使用 nacos 创建一个可配置客户端的服务注册中心,需要传入自行配置的客户端。可自定义服务注册中心配置。 - -函数签名: - -```go -func NewNacosRegistry(client naming_client.INamingClient, opts ...RegistryOption) registry.Registry -``` - -示例代码: - -```go -func main() { - // ... - cli, err := clients.NewNamingClient( - vo.NacosClientParam{ - ClientConfig: &cc, - ServerConfigs: sc, - }, - ) - // ... - r := nacos.NewNacosRegistry(cli) - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - // ... -} -``` - -## 服务发现 - -### Option - -Nacos 拓展在服务发现部分中提供了 option 配置。 - -#### WithResolverCluster - -Nacos 扩展提供了 `WithResolverCluster` 用于帮助用户配置自定义的集群。默认为“DEFAULT” 。 - -函数签名: - -```go -func WithResolverCluster(cluster string) ResolverOption -``` - -示例代码: - -```go -func main() { - client, err := client.NewClient() - if err != nil { - panic(err) - } - r, err := nacos.NewDefaultNacosResolver( - nacos.WithResolverCluster("Cluster123"), - ) - if err != nil { - log.Fatal(err) - return - } - client.Use(sd.Discovery(r)) - // ... -} -``` - -#### WithResolverGroup - -Nacos 扩展提供了 `WithResolverGroup` 用于帮助用户配置自定义的集群。默认为 "DEFAULT_GROUP" 。 - -函数签名: - -```go -func WithResolverGroup(group string) ResolverOption -``` - -示例代码: - -```go -func main() { - client, err := client.NewClient() - if err != nil { - panic(err) - } - r, err := nacos.NewDefaultNacosResolver( - nacos.WithResolverGroup("Group1"), - ) - if err != nil { - log.Fatal(err) - return - } - client.Use(sd.Discovery(r)) - // ... -} -``` - -### NewDefaultNacosResolver - -`NewDefaultNacosResolver` 使用 nacos 创建一个默认的服务发现中心。会调用 `NewDefaultNacosConfig` 读取环境变量来创建一个默认的 nacos 客户端,并设置 RegionId 为 `cn-hangzhou`,且不会在启动时自动预加载服务实例信息到本地缓存。可自定义服务注册中心配置。 - -环境变量: - -| 环境变量名 | 环境变量默认值 | 描述 | -| ---------- | -------------- | ----------------------- | -| serverAddr | 127.0.0.1 | nacos 服务器地址 | -| serverPort | 8848 | nacos 服务器端口 | -| namespace | | nacos 中的 namespace Id | - -函数签名: - -```go -func NewDefaultNacosResolver(opts ...ResolverOption) (discovery.Resolver, error) -``` - -示例代码: - -```go -func main() { - client, err := client.NewClient() - if err != nil { - panic(err) - } - r, err := nacos.NewDefaultNacosResolver() - if err != nil { - log.Fatal(err) - return - } - client.Use(sd.Discovery(r)) - // ... -} -``` - -### NewNacosResolver - -`NewNacosResolver` 使用 nacos 创建一个可配置客户端的服务发现中心,需要传入自行配置的客户端。可自定义服务发现中心配置。 - -函数签名: - -```go -func NewNacosResolver(cli naming_client.INamingClient, opts ...ResolverOption) discovery.Resolver -``` - -示例代码: - -```go -func main() { - cli, err := client.NewClient() - if err != nil { - panic(err) - } - // ... - nacosCli, err := clients.NewNamingClient( - vo.NacosClientParam{ - ClientConfig: &cc, - ServerConfigs: sc, - }) - if err != nil { - panic(err) - } - r := nacos.NewNacosResolver(nacosCli) - cli.Use(sd.Discovery(r)) - // ... -} -``` - -## 使用示例 - -### 服务端 - -- 使用 `server.WithRegistry` 设置注册扩展以及注册信息。 - -```go -import ( - "context" - "log" - - "github.com/cloudwego/hertz/pkg/app" - "github.com/cloudwego/hertz/pkg/app/server" - "github.com/cloudwego/hertz/pkg/app/server/registry" - "github.com/cloudwego/hertz/pkg/common/utils" - "github.com/cloudwego/hertz/pkg/protocol/consts" - "github.com/hertz-contrib/registry/nacos" -) - -func main() { - addr := "127.0.0.1:8888" - r, err := nacos.NewDefaultNacosRegistry() - if err != nil { - log.Fatal(err) - return - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { - ctx.JSON(consts.StatusOK, utils.H{"ping": "pong"}) - }) - h.Spin() -} -``` - -### 客户端 - -- 使用内置的 `sd.Discovery` 中间件,支持传入自定义的服务发现扩展以及负载均衡扩展。 -- 使用服务发现时需要将 url 中的域名替换为服务名,并使用 `config.WithSD` 确定本次请求使用服务注册。 - -```go -import ( - "context" - "log" - - "github.com/cloudwego/hertz/pkg/app/client" - "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" - "github.com/cloudwego/hertz/pkg/common/config" - "github.com/cloudwego/hertz/pkg/common/hlog" - "github.com/hertz-contrib/registry/nacos" -) - -func main() { - client, err := client.NewClient() - if err != nil { - panic(err) - } - r, err := nacos.NewDefaultNacosResolver() - if err != nil { - log.Fatal(err) - return - } - client.Use(sd.Discovery(r)) - for i := 0; i < 10; i++ { - status, body, err := client.Get(context.Background(), nil, "http://hertz.test.demo/ping", config.WithSD(true)) - if err != nil { - hlog.Fatal(err) - } - hlog.Infof("code=%d,body=%s\n", status, string(body)) - } -} -``` - -## 注意 - -- nacos/v2 版本中 hertz 目前不支持多次在同分组下创建多端口示例 -- nacos/v2 的服务注册与发现和先前的版本兼容 -- nacos-sdk-go v2 版本中 constant.ClientConfig 中 CustomLogger 类型被移除 -- nacos/v2 只支持 nacos 2.X 版本 - -## 配置 - -可自定义 Nacos 客户端以及服务端的配置,参考 [nacos-sdk-go](https://github.com/nacos-group/nacos-sdk-go) 配置。 - -## 完整示例 - -完整用法示例详见 [example](https://github.com/hertz-contrib/registry/tree/main/nacos/examples) 。 +--- +title: "nacos" +date: 2023-04-22 +weight: 2 +keywords: ["服务注册与发现", "nacos"] +description: "Hertz 提供的服务注册与发现 nacos 拓展。" +--- + +## 安装 + +- nacos-sdk-go v1 版本 + +```go +go get github.com/hertz-contrib/registry/nacos +``` + +- nacos-sdk-go v2 版本 + +```go +go get github.com/hertz-contrib/registry/nacos/v2 +``` + +## 服务注册 + +### Option + +Nacos 拓展在服务注册部分中提供了 option 配置。 + +#### WithRegistryCluster + +Nacos 扩展提供了 `WithRegistryCluster` 用于帮助用户配置自定义的集群。默认为“DEFAULT” 。 + +函数签名: + +```go +func WithRegistryCluster(cluster string) RegistryOption +``` + +示例代码: + +```go +func main() { + // ... + r, err := nacos.NewDefaultNacosRegistry( + nacos.WithRegistryCluster("Cluster123"), + ) + if err != nil { + log.Fatal(err) + return + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +#### WithRegistryGroup + +Nacos 扩展提供了 `WithRegistryGroup` 用于帮助用户配置自定义的集群。默认为 "DEFAULT_GROUP" 。 + +函数签名: + +```go +func WithRegistryGroup(group string) RegistryOption +``` + +示例代码: + +```go +func main() { + // ... + r, err := nacos.NewDefaultNacosRegistry( + nacos.WithRegistryGroup("Group1"), + ) + if err != nil { + log.Fatal(err) + return + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +### NewDefaultNacosRegistry + +`NewDefaultNacosRegistry` 使用 nacos 创建一个默认的服务注册中心。会调用 `NewDefaultNacosConfig` 读取环境变量来创建一个默认的 nacos 客户端,并设置 RegionId 为 `cn-hangzhou`,且不会在启动时自动预加载服务实例信息到本地缓存。可自定义服务注册中心配置。 + +环境变量: + +| 环境变量名 | 环境变量默认值 | 描述 | +| ---------- | -------------- | ----------------------- | +| serverAddr | 127.0.0.1 | nacos 服务器地址 | +| serverPort | 8848 | nacos 服务器端口 | +| namespace | | nacos 中的 namespace Id | + +函数签名: + +```go +func NewDefaultNacosRegistry(opts ...RegistryOption) (registry.Registry, error) +``` + +示例代码: + +```go +func main() { + // ... + r, err := nacos.NewDefaultNacosRegistry() + if err != nil { + log.Fatal(err) + return + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +### NewNacosRegistry + +`NewNacosRegistry` 使用 nacos 创建一个可配置客户端的服务注册中心,需要传入自行配置的客户端。可自定义服务注册中心配置。 + +函数签名: + +```go +func NewNacosRegistry(client naming_client.INamingClient, opts ...RegistryOption) registry.Registry +``` + +示例代码: + +```go +func main() { + // ... + cli, err := clients.NewNamingClient( + vo.NacosClientParam{ + ClientConfig: &cc, + ServerConfigs: sc, + }, + ) + // ... + r := nacos.NewNacosRegistry(cli) + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + // ... +} +``` + +## 服务发现 + +### Option + +Nacos 拓展在服务发现部分中提供了 option 配置。 + +#### WithResolverCluster + +Nacos 扩展提供了 `WithResolverCluster` 用于帮助用户配置自定义的集群。默认为“DEFAULT” 。 + +函数签名: + +```go +func WithResolverCluster(cluster string) ResolverOption +``` + +示例代码: + +```go +func main() { + client, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := nacos.NewDefaultNacosResolver( + nacos.WithResolverCluster("Cluster123"), + ) + if err != nil { + log.Fatal(err) + return + } + client.Use(sd.Discovery(r)) + // ... +} +``` + +#### WithResolverGroup + +Nacos 扩展提供了 `WithResolverGroup` 用于帮助用户配置自定义的集群。默认为 "DEFAULT_GROUP" 。 + +函数签名: + +```go +func WithResolverGroup(group string) ResolverOption +``` + +示例代码: + +```go +func main() { + client, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := nacos.NewDefaultNacosResolver( + nacos.WithResolverGroup("Group1"), + ) + if err != nil { + log.Fatal(err) + return + } + client.Use(sd.Discovery(r)) + // ... +} +``` + +### NewDefaultNacosResolver + +`NewDefaultNacosResolver` 使用 nacos 创建一个默认的服务发现中心。会调用 `NewDefaultNacosConfig` 读取环境变量来创建一个默认的 nacos 客户端,并设置 RegionId 为 `cn-hangzhou`,且不会在启动时自动预加载服务实例信息到本地缓存。可自定义服务注册中心配置。 + +环境变量: + +| 环境变量名 | 环境变量默认值 | 描述 | +| ---------- | -------------- | ----------------------- | +| serverAddr | 127.0.0.1 | nacos 服务器地址 | +| serverPort | 8848 | nacos 服务器端口 | +| namespace | | nacos 中的 namespace Id | + +函数签名: + +```go +func NewDefaultNacosResolver(opts ...ResolverOption) (discovery.Resolver, error) +``` + +示例代码: + +```go +func main() { + client, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := nacos.NewDefaultNacosResolver() + if err != nil { + log.Fatal(err) + return + } + client.Use(sd.Discovery(r)) + // ... +} +``` + +### NewNacosResolver + +`NewNacosResolver` 使用 nacos 创建一个可配置客户端的服务发现中心,需要传入自行配置的客户端。可自定义服务发现中心配置。 + +函数签名: + +```go +func NewNacosResolver(cli naming_client.INamingClient, opts ...ResolverOption) discovery.Resolver +``` + +示例代码: + +```go +func main() { + cli, err := client.NewClient() + if err != nil { + panic(err) + } + // ... + nacosCli, err := clients.NewNamingClient( + vo.NacosClientParam{ + ClientConfig: &cc, + ServerConfigs: sc, + }) + if err != nil { + panic(err) + } + r := nacos.NewNacosResolver(nacosCli) + cli.Use(sd.Discovery(r)) + // ... +} +``` + +## 使用示例 + +### 服务端 + +- 使用 `server.WithRegistry` 设置注册扩展以及注册信息。 + +```go +import ( + "context" + "log" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/protocol/consts" + "github.com/hertz-contrib/registry/nacos" +) + +func main() { + addr := "127.0.0.1:8888" + r, err := nacos.NewDefaultNacosRegistry() + if err != nil { + log.Fatal(err) + return + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { + ctx.JSON(consts.StatusOK, utils.H{"ping": "pong"}) + }) + h.Spin() +} +``` + +### 客户端 + +- 使用内置的 `sd.Discovery` 中间件,支持传入自定义的服务发现扩展以及负载均衡扩展。 +- 使用服务发现时需要将 url 中的域名替换为服务名,并使用 `config.WithSD` 确定本次请求使用服务注册。 + +```go +import ( + "context" + "log" + + "github.com/cloudwego/hertz/pkg/app/client" + "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" + "github.com/cloudwego/hertz/pkg/common/config" + "github.com/cloudwego/hertz/pkg/common/hlog" + "github.com/hertz-contrib/registry/nacos" +) + +func main() { + client, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := nacos.NewDefaultNacosResolver() + if err != nil { + log.Fatal(err) + return + } + client.Use(sd.Discovery(r)) + for i := 0; i < 10; i++ { + status, body, err := client.Get(context.Background(), nil, "http://hertz.test.demo/ping", config.WithSD(true)) + if err != nil { + hlog.Fatal(err) + } + hlog.Infof("code=%d,body=%s\n", status, string(body)) + } +} +``` + +## 注意 + +- nacos/v2 版本中 hertz 目前不支持多次在同分组下创建多端口示例 +- nacos/v2 的服务注册与发现和先前的版本兼容 +- nacos-sdk-go v2 版本中 constant.ClientConfig 中 CustomLogger 类型被移除 +- nacos/v2 只支持 nacos 2.X 版本 + +## 配置 + +可自定义 Nacos 客户端以及服务端的配置,参考 [nacos-sdk-go](https://github.com/nacos-group/nacos-sdk-go) 配置。 + +## 完整示例 + +完整用法示例详见 [example](https://github.com/hertz-contrib/registry/tree/main/nacos/examples) 。 diff --git a/content/zh/docs/hertz/tutorials/service-governance/service_discovery/polaris.md b/content/zh/docs/hertz/tutorials/service-governance/service_discovery/polaris.md index db68658731..5507c52b32 100644 --- a/content/zh/docs/hertz/tutorials/service-governance/service_discovery/polaris.md +++ b/content/zh/docs/hertz/tutorials/service-governance/service_discovery/polaris.md @@ -1,173 +1,173 @@ ---- -title: "polaris" -date: 2023-04-22 -weight: 6 -keywords: ["服务注册与发现", "polaris"] -description: "Hertz 提供的服务注册与发现 polaris 拓展。" ---- - -## 安装 - -```go -go get github.com/hertz-contrib/registry/polaris -``` - -## 服务注册 - -### NewPolarisRegistry - -`NewPolarisRegistry` 使用 polaris 创建一个新的服务注册中心,可传入配置文件并调用 `GetPolarisConfig`,若不传入则使用默认配置。 - -函数签名: - -```go -func NewPolarisRegistry(configFile ...string) (Registry, error) -``` - -示例代码: - -```go -func main() { - r, err := polaris.NewPolarisRegistry(confPath) - if err != nil { - log.Fatal(err) - } - - Info := ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", "127.0.0.1:8888"), - Tags: map[string]string{ - "namespace": Namespace, - }, - } - h := server.Default(server.WithRegistry(r, Info), server.WithExitWaitTime(10*time.Second)) - // ... -} -``` - -## 服务发现 - -### NewPolarisResolver - -`NewPolarisResolver` 使用 polaris 创建一个新的服务发现中心,可传入配置文件并调用 `GetPolarisConfig`,若不传入则使用默认配置。 - -函数签名: - -```go -func NewPolarisResolver(configFile ...string) (Resolver, error) -``` - -示例代码: - -```go -func main() { - r, err := polaris.NewPolarisResolver(confPath) - if err != nil { - log.Fatal(err) - } - - client, err := hclient.NewClient() - client.Use(sd.Discovery(r)) - //... -} -``` - -## 使用示例 - -### 服务端 - -```go -import ( - "context" - "log" - "time" - - "github.com/cloudwego/hertz/pkg/app" - "github.com/cloudwego/hertz/pkg/app/server" - "github.com/cloudwego/hertz/pkg/app/server/registry" - "github.com/cloudwego/hertz/pkg/common/utils" - "github.com/cloudwego/hertz/pkg/protocol/consts" - "github.com/hertz-contrib/registry/polaris" -) - -const ( - confPath = "polaris.yaml" - Namespace = "Polaris" - // At present,polaris server tag is v1.4.0,can't support auto create namespace, - // If you want to use a namespace other than default,Polaris ,before you register an instance, - // you should create the namespace at polaris console first. -) - -func main() { - r, err := polaris.NewPolarisRegistry(confPath) - - if err != nil { - log.Fatal(err) - } - - Info := ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", "127.0.0.1:8888"), - Tags: map[string]string{ - "namespace": Namespace, - }, - } - h := server.Default(server.WithRegistry(r, Info), server.WithExitWaitTime(10*time.Second)) - - h.GET("/hello", func(ctx context.Context, c *app.RequestContext) { - c.String(consts.StatusOK, "Hello,Hertz!") - }) - - h.Spin() -} -``` - -### 客户端 - -```go -import ( - "context" - "log" - - hclient "github.com/cloudwego/hertz/pkg/app/client" - "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" - "github.com/cloudwego/hertz/pkg/common/config" - "github.com/cloudwego/hertz/pkg/common/hlog" - "github.com/hertz-contrib/registry/polaris" -) - -const ( - confPath = "polaris.yaml" - Namespace = "Polaris" - // At present,polaris server tag is v1.4.0,can't support auto create namespace, - // if you want to use a namespace other than default,Polaris ,before you register an instance, - // you should create the namespace at polaris console first. -) - -func main() { - r, err := polaris.NewPolarisResolver(confPath) - if err != nil { - log.Fatal(err) - } - - client, err := hclient.NewClient() - client.Use(sd.Discovery(r)) - - for i := 0; i < 10; i++ { - // config.WithTag sets the namespace tag for service discovery - status, body, err := client.Get(context.TODO(), nil, "http://hertz.test.demo/hello", config.WithSD(true), config.WithTag("namespace", Namespace)) - if err != nil { - hlog.Fatal(err) - } - hlog.Infof("code=%d,body=%s\n", status, body) - } -} -``` - -## 配置 - -可自定义 polaris 客户端以及服务端的配置,参考 [polaris-go](https://pkg.go.dev/github.com/polarismesh/polaris-go/api#section-readme) 配置。 - -## 完整示例 - -完整用法示例详见 [example](https://github.com/hertz-contrib/registry/tree/main/polaris/example) 。 +--- +title: "polaris" +date: 2023-04-22 +weight: 6 +keywords: ["服务注册与发现", "polaris"] +description: "Hertz 提供的服务注册与发现 polaris 拓展。" +--- + +## 安装 + +```go +go get github.com/hertz-contrib/registry/polaris +``` + +## 服务注册 + +### NewPolarisRegistry + +`NewPolarisRegistry` 使用 polaris 创建一个新的服务注册中心,可传入配置文件并调用 `GetPolarisConfig`,若不传入则使用默认配置。 + +函数签名: + +```go +func NewPolarisRegistry(configFile ...string) (Registry, error) +``` + +示例代码: + +```go +func main() { + r, err := polaris.NewPolarisRegistry(confPath) + if err != nil { + log.Fatal(err) + } + + Info := ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", "127.0.0.1:8888"), + Tags: map[string]string{ + "namespace": Namespace, + }, + } + h := server.Default(server.WithRegistry(r, Info), server.WithExitWaitTime(10*time.Second)) + // ... +} +``` + +## 服务发现 + +### NewPolarisResolver + +`NewPolarisResolver` 使用 polaris 创建一个新的服务发现中心,可传入配置文件并调用 `GetPolarisConfig`,若不传入则使用默认配置。 + +函数签名: + +```go +func NewPolarisResolver(configFile ...string) (Resolver, error) +``` + +示例代码: + +```go +func main() { + r, err := polaris.NewPolarisResolver(confPath) + if err != nil { + log.Fatal(err) + } + + client, err := hclient.NewClient() + client.Use(sd.Discovery(r)) + //... +} +``` + +## 使用示例 + +### 服务端 + +```go +import ( + "context" + "log" + "time" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/protocol/consts" + "github.com/hertz-contrib/registry/polaris" +) + +const ( + confPath = "polaris.yaml" + Namespace = "Polaris" + // At present,polaris server tag is v1.4.0,can't support auto create namespace, + // If you want to use a namespace other than default,Polaris ,before you register an instance, + // you should create the namespace at polaris console first. +) + +func main() { + r, err := polaris.NewPolarisRegistry(confPath) + + if err != nil { + log.Fatal(err) + } + + Info := ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", "127.0.0.1:8888"), + Tags: map[string]string{ + "namespace": Namespace, + }, + } + h := server.Default(server.WithRegistry(r, Info), server.WithExitWaitTime(10*time.Second)) + + h.GET("/hello", func(ctx context.Context, c *app.RequestContext) { + c.String(consts.StatusOK, "Hello,Hertz!") + }) + + h.Spin() +} +``` + +### 客户端 + +```go +import ( + "context" + "log" + + hclient "github.com/cloudwego/hertz/pkg/app/client" + "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" + "github.com/cloudwego/hertz/pkg/common/config" + "github.com/cloudwego/hertz/pkg/common/hlog" + "github.com/hertz-contrib/registry/polaris" +) + +const ( + confPath = "polaris.yaml" + Namespace = "Polaris" + // At present,polaris server tag is v1.4.0,can't support auto create namespace, + // if you want to use a namespace other than default,Polaris ,before you register an instance, + // you should create the namespace at polaris console first. +) + +func main() { + r, err := polaris.NewPolarisResolver(confPath) + if err != nil { + log.Fatal(err) + } + + client, err := hclient.NewClient() + client.Use(sd.Discovery(r)) + + for i := 0; i < 10; i++ { + // config.WithTag sets the namespace tag for service discovery + status, body, err := client.Get(context.TODO(), nil, "http://hertz.test.demo/hello", config.WithSD(true), config.WithTag("namespace", Namespace)) + if err != nil { + hlog.Fatal(err) + } + hlog.Infof("code=%d,body=%s\n", status, body) + } +} +``` + +## 配置 + +可自定义 polaris 客户端以及服务端的配置,参考 [polaris-go](https://pkg.go.dev/github.com/polarismesh/polaris-go/api#section-readme) 配置。 + +## 完整示例 + +完整用法示例详见 [example](https://github.com/hertz-contrib/registry/tree/main/polaris/example) 。 diff --git a/content/zh/docs/hertz/tutorials/service-governance/service_discovery/redis.md b/content/zh/docs/hertz/tutorials/service-governance/service_discovery/redis.md index b0d242236e..e2670e8ce4 100644 --- a/content/zh/docs/hertz/tutorials/service-governance/service_discovery/redis.md +++ b/content/zh/docs/hertz/tutorials/service-governance/service_discovery/redis.md @@ -1,531 +1,531 @@ ---- -title: "redis" -date: 2023-04-22 -weight: 9 -keywords: ["服务注册与发现", "redis"] -description: "Hertz 提供的服务注册与发现 redis 拓展。" ---- - -## 安装 - -```go -go get github.com/hertz-contrib/registry/redis -``` - -## 服务注册 - -### Option - -Redis 拓展在服务注册部分中提供了 option 配置。 - -#### WithExpireTime - -Redis 扩展提供了 `WithExpireTime` 配置存储服务信息的 Key 的过期时间(秒为单位)。默认为 60 秒。 - -**注意:过期时间必须大于刷新间隔。** - -函数签名: - -```go -func WithExpireTime(time int) Option -``` - -示例代码: - -```go -func main() { - r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithExpireTime(10)) - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -#### WithRefreshInterval - -Redis 扩展提供了 `WithRefreshInterval` 配置存储服务信息的 Key 的过期时间刷新间隔(秒为单位)。默认为 30 秒。 - -**注意:刷新间隔必须小于过期时间。** - -函数签名: - -```go -func WithRefreshInterval(interval int) Option -``` - -示例代码: - -```go -func main() { - r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithRereshInterval(5)) - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -#### WithPassword - -Redis 扩展提供了 `WithPassword` 配置 redis 的密码,此密码必须匹配服务器配置选项中指定的密码。默认为空。 - -函数签名: - -```go -func WithPassword(password string) Option -``` - -示例代码: - -```go -func main() { - r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithPassword("123456")) - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -#### WithDB - -Redis 扩展提供了 `WithDB` 配置连接到服务器后要选择的数据库。默认为 0。 - -函数签名: - -```go -func WithDB(db int) Option -``` - -示例代码: - -```go -func main() { - r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithDB(1)) - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -#### WithTLSConfig - -Redis 扩展提供了 `WithTLSConfig` 配置 TLS 的配置项。 - -函数签名: - -```go -func WithTLSConfig(t *tls.Config) Option -``` - -示例代码: - -```go -func main() { - r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithTLSConfig(&tls.Config{ - // ... - })) - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -#### WithDialer - -Redis 扩展提供了 `WithDialer` 配置 Dialer,Dialer 将会创建新的网络连接并优先于 Network 和 Addr 选项。 - -函数签名: - -```go -func WithDialer(dialer func(ctx context.Context, network, addr string) (net.Conn, error)) Option -``` - -示例代码: - -```go -func main() { - r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithDialer( - // ... - )) - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -#### WithReadTimeout - -Redis 扩展提供了 `WithReadTimeout` 配置读取 socket 超时的时间,默认为 3 秒。 - -函数签名: - -```go -func WithReadTimeout(t time.Duration) Option -``` - -示例代码: - -```go -func main() { - r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithReadTimeout(5*time.Second)) - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -#### WithWriteTimeout - -Redis 扩展提供了 `WithWriteTimeout` 配置写入 socket 超时的时间,默认等同于 `ReadTimeout`。 - -函数签名: - -```go -func WithWriteTimeout(t time.Duration) Option -``` - -示例代码: - -```go -func main() { - r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithWriteTimeout(5*time.Second)) - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -### NewRedisRegistry - -`NewRedisRegistry` 使用 redis 创建一个新的服务注册中心,需要传入目标地址。可自定义客户端配置并传入 `NewClient` 创建一个新的客户端。 - -函数签名: - -```go -func NewRedisRegistry(addr string, opts ...Option) registry.Registry -``` - -示例代码: - -```go -func main() { - r := redis.NewRedisRegistry("127.0.0.1:6379") - // ... - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -## 服务发现 - -### Option - -Redis 拓展在服务发现部分中提供了 option 配置。 - -#### WithPassword - -Redis 扩展提供了 `WithPassword` 配置 redis 的密码,此密码必须匹配服务器配置选项中指定的密码。默认为空。 - -函数签名: - -```go -func WithPassword(password string) Option -``` - -示例代码: - -```go -func main() { - cli, err := client.NewClient() - // ... - r := redis.NewRedisResolver("127.0.0.1:6379", redis.WithPassword("123456")) - cli.Use(sd.Discovery(r)) - // ... -} -``` - -#### WithDB - -Redis 扩展提供了 `WithDB` 配置连接到服务器后要选择的数据库。默认为 0。 - -函数签名: - -```go -func WithDB(db int) Option -``` - -示例代码: - -```go -func main() { - cli, err := client.NewClient() - // ... - r := redis.NewRedisResolver("127.0.0.1:6379", redis.WithDB(1)) - cli.Use(sd.Discovery(r)) - // ... -} -``` - -#### WithTLSConfig - -Redis 扩展提供了 `WithTLSConfig` 配置 TLS 的配置项。 - -函数签名: - -```go -func WithTLSConfig(t *tls.Config) Option -``` - -示例代码: - -```go -func main() { - cli, err := client.NewClient() - // ... - r := redis.NewRedisResolver("127.0.0.1:6379", redis.WithTLSConfig(&tls.Config{ - // ... - })) - cli.Use(sd.Discovery(r)) - // ... -} -``` - -#### WithDialer - -Redis 扩展提供了 `WithDialer` 配置 Dialer,Dialer 将会创建新的网络连接并优先于 Network 和 Addr 选项。 - -函数签名: - -```go -func WithDialer(dialer func(ctx context.Context, network, addr string) (net.Conn, error)) Option -``` - -示例代码: - -```go -func main() { - cli, err := client.NewClient() - // ... - r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithDialer( - // ... - )) - cli.Use(sd.Discovery(r)) - // ... -} -``` - -#### WithReadTimeout - -Redis 扩展提供了 `WithReadTimeout` 配置读取 socket 超时的时间,默认为 3 秒。 - -函数签名: - -```go -func WithReadTimeout(t time.Duration) Option -``` - -示例代码: - -```go -func main() { - cli, err := client.NewClient() - // ... - r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithReadTimeout(5*time.Second)) - // ... - cli.Use(sd.Discovery(r)) - // ... -} -``` - -#### WithWriteTimeout - -Redis 扩展提供了 `WithWriteTimeout` 配置写入 socket 超时的时间,默认等同于 `ReadTimeout`。 - -函数签名: - -```go -func WithWriteTimeout(t time.Duration) Option -``` - -示例代码: - -```go -func main() { - cli, err := client.NewClient() - // ... - r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithWriteTimeout(5*time.Second)) - // ... - cli.Use(sd.Discovery(r)) - // ... -} -``` - -### NewRedisResolver - -`NewRedisResolver` 使用 redis 创建一个新的服务发现中心,需要传入目标地址。可自定义客户端配置并传入 `NewClient` 创建一个新的客户端。 - -函数签名: - -```go -func NewRedisResolver(addr string, opts ...Option) discovery.Resolver -``` - -示例代码: - -```go -func main() { - cli, err := client.NewClient() - // ... - r := redis.NewRedisResolver("127.0.0.1:6379") - cli.Use(sd.Discovery(r)) - // ... -} -``` - -## 使用示例 - -### 服务端 - -```go -package main - -import ( - "context" - - "github.com/cloudwego/hertz/pkg/app" - "github.com/cloudwego/hertz/pkg/app/server" - "github.com/cloudwego/hertz/pkg/app/server/registry" - "github.com/cloudwego/hertz/pkg/common/utils" - "github.com/cloudwego/hertz/pkg/protocol/consts" - "github.com/hertz-contrib/registry/redis" -) - -func main() { - r := redis.NewRedisRegistry("127.0.0.1:6379") - addr := "127.0.0.1:8888" - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - h.GET("/ping", func(_ context.Context, ctx *app.RequestContext) { - ctx.JSON(consts.StatusOK, utils.H{"ping": "pong"}) - }) - h.Spin() -} -``` - -### 客户端 - -```go -package main - -import ( - "context" - - "github.com/cloudwego/hertz/pkg/app/client" - "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" - "github.com/cloudwego/hertz/pkg/common/config" - "github.com/cloudwego/hertz/pkg/common/hlog" - "github.com/hertz-contrib/registry/redis" -) - -func main() { - cli, err := client.NewClient() - if err != nil { - panic(err) - } - r := redis.NewRedisResolver("127.0.0.1:6379") - cli.Use(sd.Discovery(r)) - for i := 0; i < 10; i++ { - status, body, err := cli.Get(context.Background(), nil, "http://hertz.test.demo/ping", config.WithSD(true)) - if err != nil { - hlog.Fatal(err) - } - hlog.Infof("HERTZ: code=%d,body=%s", status, string(body)) - } -} -``` - -## 配置 - -可自定义 redis 客户端以及服务端的配置,参考 [go-redis](https://github.com/go-redis/redis) 配置。 - -## 完整示例 - -完整用法示例详见 [example](https://github.com/hertz-contrib/registry/tree/main/redis/example) 。 +--- +title: "redis" +date: 2023-04-22 +weight: 9 +keywords: ["服务注册与发现", "redis"] +description: "Hertz 提供的服务注册与发现 redis 拓展。" +--- + +## 安装 + +```go +go get github.com/hertz-contrib/registry/redis +``` + +## 服务注册 + +### Option + +Redis 拓展在服务注册部分中提供了 option 配置。 + +#### WithExpireTime + +Redis 扩展提供了 `WithExpireTime` 配置存储服务信息的 Key 的过期时间(秒为单位)。默认为 60 秒。 + +**注意:过期时间必须大于刷新间隔。** + +函数签名: + +```go +func WithExpireTime(time int) Option +``` + +示例代码: + +```go +func main() { + r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithExpireTime(10)) + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +#### WithRefreshInterval + +Redis 扩展提供了 `WithRefreshInterval` 配置存储服务信息的 Key 的过期时间刷新间隔(秒为单位)。默认为 30 秒。 + +**注意:刷新间隔必须小于过期时间。** + +函数签名: + +```go +func WithRefreshInterval(interval int) Option +``` + +示例代码: + +```go +func main() { + r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithRereshInterval(5)) + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +#### WithPassword + +Redis 扩展提供了 `WithPassword` 配置 redis 的密码,此密码必须匹配服务器配置选项中指定的密码。默认为空。 + +函数签名: + +```go +func WithPassword(password string) Option +``` + +示例代码: + +```go +func main() { + r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithPassword("123456")) + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +#### WithDB + +Redis 扩展提供了 `WithDB` 配置连接到服务器后要选择的数据库。默认为 0。 + +函数签名: + +```go +func WithDB(db int) Option +``` + +示例代码: + +```go +func main() { + r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithDB(1)) + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +#### WithTLSConfig + +Redis 扩展提供了 `WithTLSConfig` 配置 TLS 的配置项。 + +函数签名: + +```go +func WithTLSConfig(t *tls.Config) Option +``` + +示例代码: + +```go +func main() { + r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithTLSConfig(&tls.Config{ + // ... + })) + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +#### WithDialer + +Redis 扩展提供了 `WithDialer` 配置 Dialer,Dialer 将会创建新的网络连接并优先于 Network 和 Addr 选项。 + +函数签名: + +```go +func WithDialer(dialer func(ctx context.Context, network, addr string) (net.Conn, error)) Option +``` + +示例代码: + +```go +func main() { + r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithDialer( + // ... + )) + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +#### WithReadTimeout + +Redis 扩展提供了 `WithReadTimeout` 配置读取 socket 超时的时间,默认为 3 秒。 + +函数签名: + +```go +func WithReadTimeout(t time.Duration) Option +``` + +示例代码: + +```go +func main() { + r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithReadTimeout(5*time.Second)) + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +#### WithWriteTimeout + +Redis 扩展提供了 `WithWriteTimeout` 配置写入 socket 超时的时间,默认等同于 `ReadTimeout`。 + +函数签名: + +```go +func WithWriteTimeout(t time.Duration) Option +``` + +示例代码: + +```go +func main() { + r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithWriteTimeout(5*time.Second)) + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +### NewRedisRegistry + +`NewRedisRegistry` 使用 redis 创建一个新的服务注册中心,需要传入目标地址。可自定义客户端配置并传入 `NewClient` 创建一个新的客户端。 + +函数签名: + +```go +func NewRedisRegistry(addr string, opts ...Option) registry.Registry +``` + +示例代码: + +```go +func main() { + r := redis.NewRedisRegistry("127.0.0.1:6379") + // ... + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +## 服务发现 + +### Option + +Redis 拓展在服务发现部分中提供了 option 配置。 + +#### WithPassword + +Redis 扩展提供了 `WithPassword` 配置 redis 的密码,此密码必须匹配服务器配置选项中指定的密码。默认为空。 + +函数签名: + +```go +func WithPassword(password string) Option +``` + +示例代码: + +```go +func main() { + cli, err := client.NewClient() + // ... + r := redis.NewRedisResolver("127.0.0.1:6379", redis.WithPassword("123456")) + cli.Use(sd.Discovery(r)) + // ... +} +``` + +#### WithDB + +Redis 扩展提供了 `WithDB` 配置连接到服务器后要选择的数据库。默认为 0。 + +函数签名: + +```go +func WithDB(db int) Option +``` + +示例代码: + +```go +func main() { + cli, err := client.NewClient() + // ... + r := redis.NewRedisResolver("127.0.0.1:6379", redis.WithDB(1)) + cli.Use(sd.Discovery(r)) + // ... +} +``` + +#### WithTLSConfig + +Redis 扩展提供了 `WithTLSConfig` 配置 TLS 的配置项。 + +函数签名: + +```go +func WithTLSConfig(t *tls.Config) Option +``` + +示例代码: + +```go +func main() { + cli, err := client.NewClient() + // ... + r := redis.NewRedisResolver("127.0.0.1:6379", redis.WithTLSConfig(&tls.Config{ + // ... + })) + cli.Use(sd.Discovery(r)) + // ... +} +``` + +#### WithDialer + +Redis 扩展提供了 `WithDialer` 配置 Dialer,Dialer 将会创建新的网络连接并优先于 Network 和 Addr 选项。 + +函数签名: + +```go +func WithDialer(dialer func(ctx context.Context, network, addr string) (net.Conn, error)) Option +``` + +示例代码: + +```go +func main() { + cli, err := client.NewClient() + // ... + r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithDialer( + // ... + )) + cli.Use(sd.Discovery(r)) + // ... +} +``` + +#### WithReadTimeout + +Redis 扩展提供了 `WithReadTimeout` 配置读取 socket 超时的时间,默认为 3 秒。 + +函数签名: + +```go +func WithReadTimeout(t time.Duration) Option +``` + +示例代码: + +```go +func main() { + cli, err := client.NewClient() + // ... + r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithReadTimeout(5*time.Second)) + // ... + cli.Use(sd.Discovery(r)) + // ... +} +``` + +#### WithWriteTimeout + +Redis 扩展提供了 `WithWriteTimeout` 配置写入 socket 超时的时间,默认等同于 `ReadTimeout`。 + +函数签名: + +```go +func WithWriteTimeout(t time.Duration) Option +``` + +示例代码: + +```go +func main() { + cli, err := client.NewClient() + // ... + r := redis.NewRedisRegistry("127.0.0.1:6379", redis.WithWriteTimeout(5*time.Second)) + // ... + cli.Use(sd.Discovery(r)) + // ... +} +``` + +### NewRedisResolver + +`NewRedisResolver` 使用 redis 创建一个新的服务发现中心,需要传入目标地址。可自定义客户端配置并传入 `NewClient` 创建一个新的客户端。 + +函数签名: + +```go +func NewRedisResolver(addr string, opts ...Option) discovery.Resolver +``` + +示例代码: + +```go +func main() { + cli, err := client.NewClient() + // ... + r := redis.NewRedisResolver("127.0.0.1:6379") + cli.Use(sd.Discovery(r)) + // ... +} +``` + +## 使用示例 + +### 服务端 + +```go +package main + +import ( + "context" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/protocol/consts" + "github.com/hertz-contrib/registry/redis" +) + +func main() { + r := redis.NewRedisRegistry("127.0.0.1:6379") + addr := "127.0.0.1:8888" + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + h.GET("/ping", func(_ context.Context, ctx *app.RequestContext) { + ctx.JSON(consts.StatusOK, utils.H{"ping": "pong"}) + }) + h.Spin() +} +``` + +### 客户端 + +```go +package main + +import ( + "context" + + "github.com/cloudwego/hertz/pkg/app/client" + "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" + "github.com/cloudwego/hertz/pkg/common/config" + "github.com/cloudwego/hertz/pkg/common/hlog" + "github.com/hertz-contrib/registry/redis" +) + +func main() { + cli, err := client.NewClient() + if err != nil { + panic(err) + } + r := redis.NewRedisResolver("127.0.0.1:6379") + cli.Use(sd.Discovery(r)) + for i := 0; i < 10; i++ { + status, body, err := cli.Get(context.Background(), nil, "http://hertz.test.demo/ping", config.WithSD(true)) + if err != nil { + hlog.Fatal(err) + } + hlog.Infof("HERTZ: code=%d,body=%s", status, string(body)) + } +} +``` + +## 配置 + +可自定义 redis 客户端以及服务端的配置,参考 [go-redis](https://github.com/go-redis/redis) 配置。 + +## 完整示例 + +完整用法示例详见 [example](https://github.com/hertz-contrib/registry/tree/main/redis/example) 。 diff --git a/content/zh/docs/hertz/tutorials/service-governance/service_discovery/servicecomb.md b/content/zh/docs/hertz/tutorials/service-governance/service_discovery/servicecomb.md index 5f8080be10..8f51560cb2 100644 --- a/content/zh/docs/hertz/tutorials/service-governance/service_discovery/servicecomb.md +++ b/content/zh/docs/hertz/tutorials/service-governance/service_discovery/servicecomb.md @@ -1,470 +1,470 @@ ---- -title: "servicecomb" -date: 2023-04-22 -weight: 7 -keywords: ["服务注册与发现", "servicecomb"] -description: "Hertz 提供的服务注册与发现 servicecomb 拓展。" ---- - -## 安装 - -```go -go get github.com/hertz-contrib/registry/servicecomb -``` - -## 服务注册 - -### Option - -Servicecomb 拓展在服务注册部分中提供了 option 配置。 - -#### WithAppId - -Servicecomb 扩展提供了 `WithAppId` 用于帮助用户配置 Servicecomb 的 AppId。默认为“DEFAULT" 。 - -函数签名: - -```go -func WithAppId(appId string) RegistryOption -``` - -示例代码: - -```go -func main() { - // ... - r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, - servicecomb.WithAppId("appID"), - ) - if err != nil { - log.Fatal(err) - return - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.servicecomb.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -#### WithRegistryVersionRule - -Servicecomb 扩展提供了 `WithRegistryVersionRule` 用于帮助用户配置 Servicecomb 的版本要求。默认为 1.0.0。 - -函数签名: - -```go -func WithRegistryVersionRule(versionRule string) RegistryOption -``` - -示例代码: - -```go -func main() { - // ... - r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, - servicecomb.WithRegistryVersionRule("1.1.0"), - ) - if err != nil { - log.Fatal(err) - return - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.servicecomb.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -#### WithRegistryHostName - -Servicecomb 扩展提供了 `WithRegistryHostName` 用于帮助用户配置 Servicecomb 的主机名。默认为”DEFAULT" 。 - -函数签名: - -```go -func WithRegistryHostName(hostName string) RegistryOption -``` - -示例代码: - -```go -func main() { - // ... - r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, - servicecomb.WithRegistryHostName("hostName"), - ) - if err != nil { - log.Fatal(err) - return - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.servicecomb.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -#### WithRegistryHeartbeatInterval - -Servicecomb 扩展提供了 `WithRegistryHeartbeatInterval` 用于帮助用户配置发送心跳包的间隔时长。默认为 5。 - -函数签名: - -```go -func WithRegistryHeartbeatInterval(second int32) RegistryOption -``` - -示例代码: - -```go -func main() { - // ... - r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, - servicecomb.WithRegistryHeartbeatInterval(10), - ) - if err != nil { - log.Fatal(err) - return - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.servicecomb.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -### NewDefaultSCRegistry - -`NewDefaultSCRegistry` 使用 service-comb 创建一个默认服务注册中心,需要传入端点值。可自定义服务注册中心配置。 - -函数签名: - -```go -func NewDefaultSCRegistry(endPoints []string, opts ...RegistryOption) (registry.Registry, error) -``` - -示例代码: - -```go -func main() { - // ... - r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}) - if err != nil { - log.Fatal(err) - return - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.servicecomb.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -### NewSCRegistry - -`NewSCRegistry` 使用 service-comb 创建一个新的服务注册中心。需要传入自定义客户端。可自定义服务注册中心配置。 - -函数签名: - -```go -func NewSCRegistry(client *sc.Client, opts ...RegistryOption) registry.Registry -``` - -示例代码: - -```go -func main() { - client := &sc.Client{ - // ... - } - // ... - r, err := servicecomb.NewSCRegistry(client) - if err != nil { - log.Fatal(err) - return - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.servicecomb.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - // ... -} -``` - -## 服务发现 - -### Option - -Servicecomb 拓展在服务发现部分中提供了 option 配置。 - -#### WithAppId - -Servicecomb 扩展提供了 `WithAppId` 用于帮助用户配置 Servicecomb 的 AppId。默认为“DEFAULT" 。 - -函数签名: - -```go -func WithResolverAppId(appId string) ResolverOption -``` - -示例代码: - -```go -func main() { - // ... - r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, - servicecomb.WithAppId("appID"), - ) - if err != nil { - panic(err) - } - cli, err := client.NewClient() - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - // ... -} -``` - -#### WithResolverVersionRule - -Servicecomb 扩展提供了 `WithResolverVersionRule` 用于帮助用户配置 Servicecomb 的版本要求。默认为 latest。 - -函数签名: - -```go -func WithResolverVersionRule(versionRule string) ResolverOption -``` - -示例代码: - -```go -func main() { - // ... - r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, - servicecomb.WithResolverVersionRule("1.0.0"), - ) - if err != nil { - panic(err) - } - cli, err := client.NewClient() - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - // ... -} -``` - -#### WithResolverConsumerId - -Servicecomb 扩展提供了 `WithResolverConsumerId` 用于帮助用户配置 Servicecomb 的 ConsumerId。默认为空。 - -函数签名: - -```go -func WithResolverConsumerId(consumerId string) ResolverOption -``` - -示例代码: - -```go -func main() { - // ... - r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, - servicecomb.WithResolverConsumerId("1"), - ) - if err != nil { - panic(err) - } - cli, err := client.NewClient() - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - // ... -} -``` - -### NewDefaultSCResolver - -`NewDefaultSCResolver` 使用 service-comb 创建一个默认服务发现中心,需要传入端点值。可自定义服务发现中心配置。 - -函数签名: - -```go -func NewDefaultSCResolver(endPoints []string, opts ...ResolverOption) (discovery.Resolver, error) -``` - -示例代码: - -```go -func main() { - // ... - r, err := servicecomb.NewDefaultSCResolver([]string{scAddr}) - if err != nil { - panic(err) - } - cli, err := client.NewClient() - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - // ... -} -``` - -### NewSCResolver - -`NewSCReslover` 使用 service-comb 创建一个新的服务发现中心。需要传入自定义客户端。可自定义服务发现中心配置。 - -函数签名: - -```go -func NewSCResolver(cli *sc.Client, opts ...ResolverOption) discovery.Resolver -``` - -示例代码: - -```go -func main() { - client := &sc.Client{ - // ... - } - // ... - r, err := servicecomb.NewSCResolver(client) - if err != nil { - panic(err) - } - cli, err := client.NewClient() - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - // ... -} -``` - -## 使用示例 - -### 服务端 - -```go -import ( - "context" - "log" - "sync" - - "github.com/cloudwego/hertz/pkg/app" - "github.com/cloudwego/hertz/pkg/app/server" - "github.com/cloudwego/hertz/pkg/app/server/registry" - "github.com/cloudwego/hertz/pkg/common/utils" - "github.com/cloudwego/hertz/pkg/protocol/consts" - "github.com/hertz-contrib/registry/servicecomb" -) - -func main() { - const scAddr = "127.0.0.1:30100" - const addr = "127.0.0.1:8701" - r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}) - if err != nil { - log.Fatal(err) - return - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.servicecomb.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - }), - ) - - h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { - ctx.JSON(consts.StatusOK, utils.H{"ping": "pong1"}) - }) - h.Spin() -} -``` - -### 客户端 - -```go -import ( - "context" - - "github.com/cloudwego/hertz/pkg/app/client" - "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" - "github.com/cloudwego/hertz/pkg/common/config" - "github.com/cloudwego/hertz/pkg/common/hlog" - "github.com/hertz-contrib/registry/servicecomb" -) - -func main() { - const scAddr = "127.0.0.1:30100" - // build a servicecomb resolver - r, err := servicecomb.NewDefaultSCResolver([]string{scAddr}) - if err != nil { - panic(err) - } - // build a hertz client with the servicecomb resolver - cli, err := client.NewClient() - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - for i := 0; i < 10; i++ { - status, body, err := cli.Get(context.Background(), nil, "http://hertz.servicecomb.demo/ping", config.WithSD(true)) - if err != nil { - hlog.Fatal(err) - } - hlog.Infof("code=%d,body=%s", status, string(body)) - } -} -``` - -## 配置 - -可自定义 Servicecomb 客户端以及服务端的配置,参考 [go-chassis/sc-client](https://github.com/go-chassis/sc-client) 配置 - -## 完整示例 - -完整用法示例详见 [example](https://github.com/hertz-contrib/registry/tree/main/servicecomb/example) 。 +--- +title: "servicecomb" +date: 2023-04-22 +weight: 7 +keywords: ["服务注册与发现", "servicecomb"] +description: "Hertz 提供的服务注册与发现 servicecomb 拓展。" +--- + +## 安装 + +```go +go get github.com/hertz-contrib/registry/servicecomb +``` + +## 服务注册 + +### Option + +Servicecomb 拓展在服务注册部分中提供了 option 配置。 + +#### WithAppId + +Servicecomb 扩展提供了 `WithAppId` 用于帮助用户配置 Servicecomb 的 AppId。默认为“DEFAULT" 。 + +函数签名: + +```go +func WithAppId(appId string) RegistryOption +``` + +示例代码: + +```go +func main() { + // ... + r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, + servicecomb.WithAppId("appID"), + ) + if err != nil { + log.Fatal(err) + return + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.servicecomb.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +#### WithRegistryVersionRule + +Servicecomb 扩展提供了 `WithRegistryVersionRule` 用于帮助用户配置 Servicecomb 的版本要求。默认为 1.0.0。 + +函数签名: + +```go +func WithRegistryVersionRule(versionRule string) RegistryOption +``` + +示例代码: + +```go +func main() { + // ... + r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, + servicecomb.WithRegistryVersionRule("1.1.0"), + ) + if err != nil { + log.Fatal(err) + return + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.servicecomb.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +#### WithRegistryHostName + +Servicecomb 扩展提供了 `WithRegistryHostName` 用于帮助用户配置 Servicecomb 的主机名。默认为”DEFAULT" 。 + +函数签名: + +```go +func WithRegistryHostName(hostName string) RegistryOption +``` + +示例代码: + +```go +func main() { + // ... + r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, + servicecomb.WithRegistryHostName("hostName"), + ) + if err != nil { + log.Fatal(err) + return + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.servicecomb.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +#### WithRegistryHeartbeatInterval + +Servicecomb 扩展提供了 `WithRegistryHeartbeatInterval` 用于帮助用户配置发送心跳包的间隔时长。默认为 5。 + +函数签名: + +```go +func WithRegistryHeartbeatInterval(second int32) RegistryOption +``` + +示例代码: + +```go +func main() { + // ... + r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, + servicecomb.WithRegistryHeartbeatInterval(10), + ) + if err != nil { + log.Fatal(err) + return + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.servicecomb.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +### NewDefaultSCRegistry + +`NewDefaultSCRegistry` 使用 service-comb 创建一个默认服务注册中心,需要传入端点值。可自定义服务注册中心配置。 + +函数签名: + +```go +func NewDefaultSCRegistry(endPoints []string, opts ...RegistryOption) (registry.Registry, error) +``` + +示例代码: + +```go +func main() { + // ... + r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}) + if err != nil { + log.Fatal(err) + return + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.servicecomb.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +### NewSCRegistry + +`NewSCRegistry` 使用 service-comb 创建一个新的服务注册中心。需要传入自定义客户端。可自定义服务注册中心配置。 + +函数签名: + +```go +func NewSCRegistry(client *sc.Client, opts ...RegistryOption) registry.Registry +``` + +示例代码: + +```go +func main() { + client := &sc.Client{ + // ... + } + // ... + r, err := servicecomb.NewSCRegistry(client) + if err != nil { + log.Fatal(err) + return + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.servicecomb.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + // ... +} +``` + +## 服务发现 + +### Option + +Servicecomb 拓展在服务发现部分中提供了 option 配置。 + +#### WithAppId + +Servicecomb 扩展提供了 `WithAppId` 用于帮助用户配置 Servicecomb 的 AppId。默认为“DEFAULT" 。 + +函数签名: + +```go +func WithResolverAppId(appId string) ResolverOption +``` + +示例代码: + +```go +func main() { + // ... + r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, + servicecomb.WithAppId("appID"), + ) + if err != nil { + panic(err) + } + cli, err := client.NewClient() + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + // ... +} +``` + +#### WithResolverVersionRule + +Servicecomb 扩展提供了 `WithResolverVersionRule` 用于帮助用户配置 Servicecomb 的版本要求。默认为 latest。 + +函数签名: + +```go +func WithResolverVersionRule(versionRule string) ResolverOption +``` + +示例代码: + +```go +func main() { + // ... + r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, + servicecomb.WithResolverVersionRule("1.0.0"), + ) + if err != nil { + panic(err) + } + cli, err := client.NewClient() + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + // ... +} +``` + +#### WithResolverConsumerId + +Servicecomb 扩展提供了 `WithResolverConsumerId` 用于帮助用户配置 Servicecomb 的 ConsumerId。默认为空。 + +函数签名: + +```go +func WithResolverConsumerId(consumerId string) ResolverOption +``` + +示例代码: + +```go +func main() { + // ... + r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}, + servicecomb.WithResolverConsumerId("1"), + ) + if err != nil { + panic(err) + } + cli, err := client.NewClient() + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + // ... +} +``` + +### NewDefaultSCResolver + +`NewDefaultSCResolver` 使用 service-comb 创建一个默认服务发现中心,需要传入端点值。可自定义服务发现中心配置。 + +函数签名: + +```go +func NewDefaultSCResolver(endPoints []string, opts ...ResolverOption) (discovery.Resolver, error) +``` + +示例代码: + +```go +func main() { + // ... + r, err := servicecomb.NewDefaultSCResolver([]string{scAddr}) + if err != nil { + panic(err) + } + cli, err := client.NewClient() + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + // ... +} +``` + +### NewSCResolver + +`NewSCReslover` 使用 service-comb 创建一个新的服务发现中心。需要传入自定义客户端。可自定义服务发现中心配置。 + +函数签名: + +```go +func NewSCResolver(cli *sc.Client, opts ...ResolverOption) discovery.Resolver +``` + +示例代码: + +```go +func main() { + client := &sc.Client{ + // ... + } + // ... + r, err := servicecomb.NewSCResolver(client) + if err != nil { + panic(err) + } + cli, err := client.NewClient() + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + // ... +} +``` + +## 使用示例 + +### 服务端 + +```go +import ( + "context" + "log" + "sync" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/protocol/consts" + "github.com/hertz-contrib/registry/servicecomb" +) + +func main() { + const scAddr = "127.0.0.1:30100" + const addr = "127.0.0.1:8701" + r, err := servicecomb.NewDefaultSCRegistry([]string{scAddr}) + if err != nil { + log.Fatal(err) + return + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.servicecomb.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + }), + ) + + h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { + ctx.JSON(consts.StatusOK, utils.H{"ping": "pong1"}) + }) + h.Spin() +} +``` + +### 客户端 + +```go +import ( + "context" + + "github.com/cloudwego/hertz/pkg/app/client" + "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" + "github.com/cloudwego/hertz/pkg/common/config" + "github.com/cloudwego/hertz/pkg/common/hlog" + "github.com/hertz-contrib/registry/servicecomb" +) + +func main() { + const scAddr = "127.0.0.1:30100" + // build a servicecomb resolver + r, err := servicecomb.NewDefaultSCResolver([]string{scAddr}) + if err != nil { + panic(err) + } + // build a hertz client with the servicecomb resolver + cli, err := client.NewClient() + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + for i := 0; i < 10; i++ { + status, body, err := cli.Get(context.Background(), nil, "http://hertz.servicecomb.demo/ping", config.WithSD(true)) + if err != nil { + hlog.Fatal(err) + } + hlog.Infof("code=%d,body=%s", status, string(body)) + } +} +``` + +## 配置 + +可自定义 Servicecomb 客户端以及服务端的配置,参考 [go-chassis/sc-client](https://github.com/go-chassis/sc-client) 配置 + +## 完整示例 + +完整用法示例详见 [example](https://github.com/hertz-contrib/registry/tree/main/servicecomb/example) 。 diff --git a/content/zh/docs/hertz/tutorials/service-governance/service_discovery/zookeeper.md b/content/zh/docs/hertz/tutorials/service-governance/service_discovery/zookeeper.md index b57338ad00..61cc05a4c7 100644 --- a/content/zh/docs/hertz/tutorials/service-governance/service_discovery/zookeeper.md +++ b/content/zh/docs/hertz/tutorials/service-governance/service_discovery/zookeeper.md @@ -1,213 +1,213 @@ ---- -title: "zookeeper" -date: 2023-04-22 -weight: 8 -keywords: ["服务注册与发现", "zookeeper"] -description: "Hertz 提供的服务注册与发现 zookeeper 拓展。" ---- - -## 安装 - -```go -go get github.com/hertz-contrib/registry/zookeeper -``` - -## 服务注册 - -### NewZookeeperRegistry - -`NewZookeeperRegistry` 使用 zookeeper 创建一个服务注册中心,需要将服务通过一个字符串切片与会话超时时间共同传入 `Connect`。 - -函数签名: - -```go -func NewZookeeperRegistry(servers []string, sessionTimeout time.Duration) (registry.Registry, error) -``` - -示例代码: - -```go -func main() { - // ... - r, err := zookeeper.NewZookeeperRegistry([]string{"127.0.0.1:2181"}, 40*time.Second) - if err != nil { - panic(err) - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - // ... -} -``` - -### NewZookeeperRegistryWithAuth - -`NewZookeeperRegistryWithAuth` 使用 zookeeper 创建一个服务注册中心,需要将服务通过一个字符串切片与会话超时时间共同传入 `Connect`。除此之外还需要传入用户与密码来调用 `AddAuth`,用户与密码不能为空。 - -函数签名: - -```go -func NewZookeeperRegistryWithAuth(servers []string, sessionTimeout time.Duration, user, password string) -``` - -示例代码: - -```go -func main() { - // ... - r, err := zookeeper.NewZookeeperRegistryWithAuth([]string{"127.0.0.1:2181"}, 20*time.Second, "hertzuser", "hertzpass") - if err != nil { - panic(err) - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - // ... -} -``` - -## 服务发现 - -### NewZookeeperResolver - -`NewZookeeperResolver` 使用 zookeeper 创建一个服务发现中心,需要将服务通过一个字符串切片与会话超时时间共同传入 `Connect`。 - -函数签名: - -```go -func NewZookeeperResolver(servers []string, sessionTimeout time.Duration) (discovery.Resolver, error) -``` - -示例代码: - -```go -func main() { - cli, err := client.NewClient() - if err != nil { - panic(err) - } - r, err := zookeeper.NewZookeeperResolver([]string{"127.0.0.1:2181"}, 40*time.Second) - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - // ... -} -``` - -### NewZookeeperResolverWithAuth - -`NewZookeeperResolverWithAuth` 使用 zookeeper 创建一个服务发现中心,需要将服务通过一个字符串切片与会话超时时间共同传入 `Connect`。除此之外还需要传入用户与密码来调用 `AddAuth`,用户与密码不能为空。 - -函数签名: - -```go -func NewZookeeperResolverWithAuth(servers []string, sessionTimeout time.Duration, user, password string) -``` - -示例代码: - -```go -func main() { - cli, err := client.NewClient() - if err != nil { - panic(err) - } - r, err := zookeeper.NewZookeeperResolverWithAuth([]string{"127.0.0.1:2181"}, 40*time.Second, "hertzuser", "hertzpass") - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - // ... -} -``` - -## 使用示例 - -### 服务端 - -```go -import ( - "context" - "time" - - "github.com/cloudwego/hertz/pkg/app" - "github.com/cloudwego/hertz/pkg/app/server" - "github.com/cloudwego/hertz/pkg/app/server/registry" - "github.com/cloudwego/hertz/pkg/common/utils" - "github.com/cloudwego/hertz/pkg/protocol/consts" - "github.com/hertz-contrib/registry/zookeeper" -) - -func main() { - addr := "127.0.0.1:8888" - r, err := zookeeper.NewZookeeperRegistry([]string{"127.0.0.1:2181"}, 40*time.Second) - if err != nil { - panic(err) - } - h := server.Default( - server.WithHostPorts(addr), - server.WithRegistry(r, ®istry.Info{ - ServiceName: "hertz.test.demo", - Addr: utils.NewNetAddr("tcp", addr), - Weight: 10, - Tags: nil, - })) - h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { - ctx.JSON(consts.StatusOK, utils.H{"ping": "pong2"}) - }) - h.Spin() -} -``` - -### 客户端 - -```go -import ( - "context" - "time" - - "github.com/cloudwego/hertz/pkg/app/client" - "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" - "github.com/cloudwego/hertz/pkg/common/config" - "github.com/cloudwego/hertz/pkg/common/hlog" - "github.com/hertz-contrib/registry/zookeeper" -) - -func main() { - cli, err := client.NewClient() - if err != nil { - panic(err) - } - r, err := zookeeper.NewZookeeperResolver([]string{"127.0.0.1:2181"}, 40*time.Second) - if err != nil { - panic(err) - } - cli.Use(sd.Discovery(r)) - for i := 0; i < 10; i++ { - status, body, err := cli.Get(context.Background(), nil, "http://hertz.test.demo/ping", config.WithSD(true)) - if err != nil { - hlog.Fatal(err) - } - hlog.Infof("code=%d,body=%s", status, string(body)) - } -} -``` - -## 配置 - -可自定义 zookeeper 客户端以及服务端的配置,参考 [go-zookeeper/zk](https://github.com/go-zookeeper/zk) 配置。 - -## 完整示例 - -完整用法示例详见 [example](https://github.com/hertz-contrib/registry/tree/main/zookeeper/example) 。 +--- +title: "zookeeper" +date: 2023-04-22 +weight: 8 +keywords: ["服务注册与发现", "zookeeper"] +description: "Hertz 提供的服务注册与发现 zookeeper 拓展。" +--- + +## 安装 + +```go +go get github.com/hertz-contrib/registry/zookeeper +``` + +## 服务注册 + +### NewZookeeperRegistry + +`NewZookeeperRegistry` 使用 zookeeper 创建一个服务注册中心,需要将服务通过一个字符串切片与会话超时时间共同传入 `Connect`。 + +函数签名: + +```go +func NewZookeeperRegistry(servers []string, sessionTimeout time.Duration) (registry.Registry, error) +``` + +示例代码: + +```go +func main() { + // ... + r, err := zookeeper.NewZookeeperRegistry([]string{"127.0.0.1:2181"}, 40*time.Second) + if err != nil { + panic(err) + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + // ... +} +``` + +### NewZookeeperRegistryWithAuth + +`NewZookeeperRegistryWithAuth` 使用 zookeeper 创建一个服务注册中心,需要将服务通过一个字符串切片与会话超时时间共同传入 `Connect`。除此之外还需要传入用户与密码来调用 `AddAuth`,用户与密码不能为空。 + +函数签名: + +```go +func NewZookeeperRegistryWithAuth(servers []string, sessionTimeout time.Duration, user, password string) +``` + +示例代码: + +```go +func main() { + // ... + r, err := zookeeper.NewZookeeperRegistryWithAuth([]string{"127.0.0.1:2181"}, 20*time.Second, "hertzuser", "hertzpass") + if err != nil { + panic(err) + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + // ... +} +``` + +## 服务发现 + +### NewZookeeperResolver + +`NewZookeeperResolver` 使用 zookeeper 创建一个服务发现中心,需要将服务通过一个字符串切片与会话超时时间共同传入 `Connect`。 + +函数签名: + +```go +func NewZookeeperResolver(servers []string, sessionTimeout time.Duration) (discovery.Resolver, error) +``` + +示例代码: + +```go +func main() { + cli, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := zookeeper.NewZookeeperResolver([]string{"127.0.0.1:2181"}, 40*time.Second) + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + // ... +} +``` + +### NewZookeeperResolverWithAuth + +`NewZookeeperResolverWithAuth` 使用 zookeeper 创建一个服务发现中心,需要将服务通过一个字符串切片与会话超时时间共同传入 `Connect`。除此之外还需要传入用户与密码来调用 `AddAuth`,用户与密码不能为空。 + +函数签名: + +```go +func NewZookeeperResolverWithAuth(servers []string, sessionTimeout time.Duration, user, password string) +``` + +示例代码: + +```go +func main() { + cli, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := zookeeper.NewZookeeperResolverWithAuth([]string{"127.0.0.1:2181"}, 40*time.Second, "hertzuser", "hertzpass") + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + // ... +} +``` + +## 使用示例 + +### 服务端 + +```go +import ( + "context" + "time" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/app/server/registry" + "github.com/cloudwego/hertz/pkg/common/utils" + "github.com/cloudwego/hertz/pkg/protocol/consts" + "github.com/hertz-contrib/registry/zookeeper" +) + +func main() { + addr := "127.0.0.1:8888" + r, err := zookeeper.NewZookeeperRegistry([]string{"127.0.0.1:2181"}, 40*time.Second) + if err != nil { + panic(err) + } + h := server.Default( + server.WithHostPorts(addr), + server.WithRegistry(r, ®istry.Info{ + ServiceName: "hertz.test.demo", + Addr: utils.NewNetAddr("tcp", addr), + Weight: 10, + Tags: nil, + })) + h.GET("/ping", func(c context.Context, ctx *app.RequestContext) { + ctx.JSON(consts.StatusOK, utils.H{"ping": "pong2"}) + }) + h.Spin() +} +``` + +### 客户端 + +```go +import ( + "context" + "time" + + "github.com/cloudwego/hertz/pkg/app/client" + "github.com/cloudwego/hertz/pkg/app/middlewares/client/sd" + "github.com/cloudwego/hertz/pkg/common/config" + "github.com/cloudwego/hertz/pkg/common/hlog" + "github.com/hertz-contrib/registry/zookeeper" +) + +func main() { + cli, err := client.NewClient() + if err != nil { + panic(err) + } + r, err := zookeeper.NewZookeeperResolver([]string{"127.0.0.1:2181"}, 40*time.Second) + if err != nil { + panic(err) + } + cli.Use(sd.Discovery(r)) + for i := 0; i < 10; i++ { + status, body, err := cli.Get(context.Background(), nil, "http://hertz.test.demo/ping", config.WithSD(true)) + if err != nil { + hlog.Fatal(err) + } + hlog.Infof("code=%d,body=%s", status, string(body)) + } +} +``` + +## 配置 + +可自定义 zookeeper 客户端以及服务端的配置,参考 [go-zookeeper/zk](https://github.com/go-zookeeper/zk) 配置。 + +## 完整示例 + +完整用法示例详见 [example](https://github.com/hertz-contrib/registry/tree/main/zookeeper/example) 。 diff --git a/content/zh/docs/hertz/tutorials/service-migration/_index.md b/content/zh/docs/hertz/tutorials/service-migration/_index.md index 1705cb1860..21020dc313 100644 --- a/content/zh/docs/hertz/tutorials/service-migration/_index.md +++ b/content/zh/docs/hertz/tutorials/service-migration/_index.md @@ -3,7 +3,6 @@ title: "迁移到 Hertz" weight: 7 keywords: ["迁移到 Hertz"] description: "Hertz 提供了其他框架( FastHTTP、Gin ) 迁移至 Hertz 的能力。" - --- ## 迁移脚本 diff --git a/content/zh/docs/hertz/tutorials/toolkit/_index.md b/content/zh/docs/hertz/tutorials/toolkit/_index.md index 8f7595eece..225f0c8fc0 100644 --- a/content/zh/docs/hertz/tutorials/toolkit/_index.md +++ b/content/zh/docs/hertz/tutorials/toolkit/_index.md @@ -3,5 +3,4 @@ title: "hz 代码生成" weight: 6 keywords: ["hz 代码生成"] description: "Hertz 提供的代码生成工具 hz。" - --- diff --git a/content/zh/docs/hertz/tutorials/toolkit/annotation.md b/content/zh/docs/hertz/tutorials/toolkit/annotation.md index 3fca0046af..03d091f965 100644 --- a/content/zh/docs/hertz/tutorials/toolkit/annotation.md +++ b/content/zh/docs/hertz/tutorials/toolkit/annotation.md @@ -1,8 +1,8 @@ --- -title: 'IDL 注解说明' +title: "IDL 注解说明" date: 2023-02-21 weight: 6 -keywords: [ "IDL 注解说明", "api 注解", "Field 注解", "Method 注解" ] +keywords: ["IDL 注解说明", "api 注解", "Field 注解", "Method 注解"] description: "hz 提供的 IDL 注解说明。" --- @@ -20,39 +20,39 @@ description: "hz 提供的 IDL 注解说明。" Field 注解 tag 说明可参考 [支持的-tag](/zh/docs/hertz/tutorials/basic-feature/binding-and-validate/#%E6%94%AF%E6%8C%81%E7%9A%84-tag)。 -| _Field 注解_ | | -|------------------------------------------|------------------------------------------------------------------------------------------| -| 注解 | 说明 | -| api.raw_body | 生成 "raw_body" tag | -| api.query | 生成 "query" tag | -| api.header | 生成 "header" tag | -| api.cookie | 生成 "cookie" tag | -| api.body | 生成 "json" tag | -| api.path | 生成 "path" tag | -| api.form | 生成 "form" tag | -| api.go_tag (protobuf)
go.tag (thrift) | 透传 go_tag,会生成 go_tag 里定义的内容 | -| api.vd | 生成 "vd" tag | +| _Field 注解_ | | +| ---------------------------------------- | --------------------------------------------------------------------------------------------------- | +| 注解 | 说明 | +| api.raw_body | 生成 "raw_body" tag | +| api.query | 生成 "query" tag | +| api.header | 生成 "header" tag | +| api.cookie | 生成 "cookie" tag | +| api.body | 生成 "json" tag | +| api.path | 生成 "path" tag | +| api.form | 生成 "form" tag | +| api.go_tag (protobuf)
go.tag (thrift) | 透传 go_tag,会生成 go_tag 里定义的内容 | +| api.vd | 生成 "vd" tag | | api.none | 生成 "-" tag,详情参考 [api.none 注解说明](/zh/docs/hertz/tutorials/toolkit/more-feature/api_none/) | -| _Method 注解_ | | -|-------------|------------------| -| 注解 | 说明 | -| api.get | 定义 GET 方法及路由 | -| api.post | 定义 POST 方法及路由 | -| api.put | 定义 PUT 方法及路由 | -| api.delete | 定义 DELETE 方法及路由 | -| api.patch | 定义 PATCH 方法及路由 | -| api.options | 定义 OPTIONS 方法及路由 | -| api.head | 定义 HEAD 方法及路由 | -| api.any | 定义 ANY 方法及路由 | +| _Method 注解_ | | +| ------------- | ----------------------- | +| 注解 | 说明 | +| api.get | 定义 GET 方法及路由 | +| api.post | 定义 POST 方法及路由 | +| api.put | 定义 PUT 方法及路由 | +| api.delete | 定义 DELETE 方法及路由 | +| api.patch | 定义 PATCH 方法及路由 | +| api.options | 定义 OPTIONS 方法及路由 | +| api.head | 定义 HEAD 方法及路由 | +| api.any | 定义 ANY 方法及路由 | ### hz client 除 [hz](#hz) 提供的注解外,为针对 client 的场景,额外增加了一种注解。 -| _Client 注解_ | | -|-----------------|------------------| -| 注解 | 说明 | +| _Client 注解_ | | +| --------------- | ------------------------- | +| 注解 | 说明 | | api.base_domain | 指定默认访问的请求 domain | ## 使用方法 diff --git a/content/zh/docs/hertz/tutorials/toolkit/cautions.md b/content/zh/docs/hertz/tutorials/toolkit/cautions.md index b8906154f0..087319eb5b 100644 --- a/content/zh/docs/hertz/tutorials/toolkit/cautions.md +++ b/content/zh/docs/hertz/tutorials/toolkit/cautions.md @@ -1,10 +1,11 @@ --- -title: '注意事项' +title: "注意事项" date: 2023-02-21 weight: 8 keywords: ["注意事项", "protobuf", "thrift"] description: "使用 hz 时的注意事项。" --- + ## 使用 protobuf IDL 时的 biz 层代码生成位置 hz 目前支持 [proto2](https://developers.google.com/protocol-buffers/docs/proto) / [proto3](https://developers.google.com/protocol-buffers/docs/proto3) 的语法。 @@ -21,8 +22,8 @@ hz 目前支持 [proto2](https://developers.google.com/protocol-buffers/docs/pro - go_package="github.com/a/b/biz/model/c/d": 会在 "/biz/model/c/d" 下生成 model,其中 "biz/model" 是默认的 model 生成路径,可使用 "--model_dir" 选项修改; - go_package="x/y/z": 会在 "biz/model/x/y/z" 下生成代码(相对路径补全); - go_package="biz/model/c/d": 会在"biz/model/biz/model/c/d" 下生成代码。 - -**推荐用户定义如“{$MODULE}/{$MODEL_DIR}/x/y/z” (其中 {$MODEL_DIR} 默认为"biz/model", 用户也可使用“model_dir”选项来定义) 这样的“go_package”。** + +**推荐用户定义如“{$MODULE}/{$MODEL_DIR}/x/y/z” (其中 {$MODEL_DIR} 默认为"biz/model", 用户也可使用“model_dir”选项来定义) 这样的“go_package”。** ### handler 文件的位置 @@ -66,52 +67,52 @@ router 注册文件同样会取 namespace 作为生成路径,其生成路径 1. 使用自定义路径的注意事项 - hz 为了用户使用方便,提供了自定义 handler 路径、model 路径、模板等功能。但是 hz 在创建一个新项目的时候并没有保存当前项目的信息,所以在使用 update 命令时可以认为是一种无状态的更新。因此对于同一套 idl 在 new 和 update 的时候,使用了不同的自定义信息,可能会产生重复的代码,举个例子,如下: + hz 为了用户使用方便,提供了自定义 handler 路径、model 路径、模板等功能。但是 hz 在创建一个新项目的时候并没有保存当前项目的信息,所以在使用 update 命令时可以认为是一种无状态的更新。因此对于同一套 idl 在 new 和 update 的时候,使用了不同的自定义信息,可能会产生重复的代码,举个例子,如下: - 创建新项目: + 创建新项目: - ```bash - hz new -idl demo.thrift + ```bash + hz new -idl demo.thrift - // 此时,hz 会把 model 生成在 "biz/model"下 - ``` + // 此时,hz 会把 model 生成在 "biz/model"下 + ``` - 更新项目: + 更新项目: - ```bash - hz update -idl demo.thrift --model_dir=my_model + ```bash + hz update -idl demo.thrift --model_dir=my_model - // 此时,hz 不会更新"biz/model"下的 model 代码,而是会在"my_model"下;这时"biz/model"和"my_model"下的代码就会重复,且新生成的 handler 会依赖"my_model",之前的 handler 会依赖"biz/model",这时就需要用户手动删除&改动一些代码了。 - ``` + // 此时,hz 不会更新"biz/model"下的 model 代码,而是会在"my_model"下;这时"biz/model"和"my_model"下的代码就会重复,且新生成的 handler 会依赖"my_model",之前的 handler 会依赖"biz/model",这时就需要用户手动删除&改动一些代码了。 + ``` - 因此,**我们希望用户使用 update 命令的时候,自定义的路径 "client_dir"、"model_dir"、"handler_dir",最好和 new 相同。** + 因此,**我们希望用户使用 update 命令的时候,自定义的路径 "client_dir"、"model_dir"、"handler_dir",最好和 new 相同。** 2. update handler 的行为 - hz 在 new 项目的时候会根据默认模板/自定义模板来生成 handler,其中每个 service 生成一个文件,该文件包含了该 service 定义的所有 handler 代码;如果 idl 定义了多个 service,则每个 service 都会生成一个文件,这些文件都在同一路径下;举个例子: + hz 在 new 项目的时候会根据默认模板/自定义模板来生成 handler,其中每个 service 生成一个文件,该文件包含了该 service 定义的所有 handler 代码;如果 idl 定义了多个 service,则每个 service 都会生成一个文件,这些文件都在同一路径下;举个例子: - ```thrift - // demo.thrift - namespace go hello.example + ```thrift + // demo.thrift + namespace go hello.example - service Service1 { - HelloResp Method1(1: HelloReq request) (api.get="/hello"); - } + service Service1 { + HelloResp Method1(1: HelloReq request) (api.get="/hello"); + } - service Service2 { - HelloResp Method2(1: HelloReq request) (api.get="/new"); - } + service Service2 { + HelloResp Method2(1: HelloReq request) (api.get="/new"); + } - // 那么该 idl 生成的 handler 文件如下: - ${handler_dir}/${namespace}/service1.go -> method1 - ${handler_dir}/${namespace}/service2.go -> method2 - ``` + // 那么该 idl 生成的 handler 文件如下: + ${handler_dir}/${namespace}/service1.go -> method1 + ${handler_dir}/${namespace}/service2.go -> method2 + ``` - **当该 idl 增加了新的 method 后,就会在对应 service 的文件的末尾追加 handler 模板;注意这里追加的 handler 会使用默认的模板,新生成 service 文件会根据情况使用自定义模板。** + **当该 idl 增加了新的 method 后,就会在对应 service 的文件的末尾追加 handler 模板;注意这里追加的 handler 会使用默认的模板,新生成 service 文件会根据情况使用自定义模板。** 3. update router 的行为 - hz 在 new 的时候生成的 router 代码主要有如下三个: + hz 在 new 的时候生成的 router 代码主要有如下三个: - biz/router/${namespace}/${idlName}.go: 每个主 idl 都会生成对应的路由注册代码文件,该文件以路由组的方式注册 idl 中定义的所有路由,并设置默认的中间件。 @@ -121,9 +122,9 @@ router 注册文件同样会取 namespace 作为生成路径,其生成路径 -- biz/router/register.go:该文件负责调用不同 idl 生成的路由注册;比如我在两个 idl "demo1.thrift"、"demo2.thrift" 中都定义了 service,那么这两个文件都会生成对应的路由注册代码。register.go 负责调用这两部分的路由注册函数。 +- biz/router/register.go:该文件负责调用不同 idl 生成的路由注册;比如我在两个 idl "demo1.thrift"、"demo2.thrift" 中都定义了 service,那么这两个文件都会生成对应的路由注册代码。register.go 负责调用这两部分的路由注册函数。 - 基于上述描述,给出 router 在 update 时的行为描述: + 基于上述描述,给出 router 在 update 时的行为描述: - biz/${namespace}/${idlName}.go: 每次都基于 idl 重新生成,用户不要改该文件代码,否则会丢失代码。 diff --git a/content/zh/docs/hertz/tutorials/toolkit/command.md b/content/zh/docs/hertz/tutorials/toolkit/command.md index 2328dec69f..cfe5000ab0 100644 --- a/content/zh/docs/hertz/tutorials/toolkit/command.md +++ b/content/zh/docs/hertz/tutorials/toolkit/command.md @@ -1,10 +1,11 @@ --- -title: 'hz 命令梳理' +title: "hz 命令梳理" date: 2023-02-21 weight: 7 keywords: ["hz 命令梳理", "New", "Update", "Model", "Client"] description: "hz 命令梳理。" --- + ## 命令行参数说明 #### Global @@ -58,7 +59,7 @@ USAGE: hz new [command options] [arguments...] OPTIONS: - --idl value [ --idl value ] Specify the IDL file path. (.thrift or .proto) + --idl value [ --idl value ] Specify the IDL file path. (.thrift or .proto) --service value Specify the service name. --module value, --mod value Specify the Go module name. --out_dir value Specify the project path. @@ -71,9 +72,9 @@ OPTIONS: --thriftgo value, -t value [ --thriftgo value, -t value ] Specify arguments for the thriftgo. ({flag}={value}) --protoc value, -p value [ --protoc value, -p value ] Specify arguments for the protoc. ({flag}={value}) --option_package value, -P value [ --option_package value, -P value ] Specify the package path. ({include_path}={import_path}) - --no_recurse Generate master model only. (default: false) + --no_recurse Generate master model only. (default: false) --force, -f Force new a project, which will overwrite the generated files (default: false) - --enable_extends Parse 'extends' for thrift IDL (default: false) + --enable_extends Parse 'extends' for thrift IDL (default: false) --json_enumstr Use string instead of num for json enums when idl is thrift. (default: false) --unset_omitempty Remove 'omitempty' tag for generated struct. (default: false) --pb_camel_json_tag Convert Name style for json tag to camel(Only works protobuf). (default: false) @@ -221,7 +222,7 @@ OPTIONS: --model_dir value Specify the model relative path (based on "out_dir"). --client_dir value Specify the client path. If not specified, IDL generated path is used for 'client' command; no client code is generated for 'new' command --use value Specify the model package to import for handler. - --proto_path value, -I value [ --proto_path value, -I value ] Add an IDL search path for includes. (Valid only if idl is protobuf) + --proto_path value, -I value [ --proto_path value, -I value ] Add an IDL search path for includes. (Valid only if idl is protobuf) --thriftgo value, -t value [ --thriftgo value, -t value ] Specify arguments for the thriftgo. ({flag}={value}) --protoc value, -p value [ --protoc value, -p value ] Specify arguments for the protoc. ({flag}={value}) --option_package value, -P value [ --option_package value, -P value ] Specify the package path. ({include_path}={import_path}) @@ -235,7 +236,7 @@ OPTIONS: --exclude_file value, -E value [ --exclude_file value, -E value ] Specify the files that do not need to be updated. --customize_package value Specify the path for package template. --handler_by_method Generate a separate handler file for each method. (default: false) - --protoc-plugins value [ --protoc-plugins value ] Specify plugins for the protoc. ({plugin_name}:{options}:{out_dir}) + --protoc-plugins value [ --protoc-plugins value ] Specify plugins for the protoc. ({plugin_name}:{options}:{out_dir}) --thrift-plugins value [ --thrift-plugins value ] Specify plugins for the thriftgo. ({plugin_name}:{options}) --help, -h show help (default: false) ``` @@ -353,7 +354,7 @@ OPTIONS: --thriftgo value, -t value [ --thriftgo value, -t value ] Specify arguments for the thriftgo. ({flag}={value}) --protoc value, -p value [ --protoc value, -p value ] Specify arguments for the protoc. ({flag}={value}) --no_recurse Generate master model only. (default: false) - --json_enumstr Use string instead of num for json enums when idl is thrift. (default: false) + --json_enumstr Use string instead of num for json enums when idl is thrift. (default: false) --unset_omitempty Remove 'omitempty' tag for generated struct. (default: false) --pb_camel_json_tag Convert Name style for json tag to camel(Only works protobuf). (default: false) --snake_tag Use snake_case style naming for tags. (Only works for 'form', 'query', 'json') (default: false) @@ -445,7 +446,7 @@ OPTIONS: --protoc value, -p value [ --protoc value, -p value ] Specify arguments for the protoc. ({flag}={value}) --no_recurse Generate master model only. (default: false) --enable_extends Parse 'extends' for thrift IDL (default: false) - --json_enumstr Use string instead of num for json enums when idl is thrift. (default: false) + --json_enumstr Use string instead of num for json enums when idl is thrift. (default: false) --unset_omitempty Remove 'omitempty' tag for generated struct. (default: false) --pb_camel_json_tag Convert Name style for json tag to camel(Only works protobuf). (default: false) --snake_tag Use snake_case style naming for tags. (Only works for 'form', 'query', 'json') (default: false) diff --git a/content/zh/docs/hertz/tutorials/toolkit/install.md b/content/zh/docs/hertz/tutorials/toolkit/install.md index 7fd2a115b7..428a985c5f 100644 --- a/content/zh/docs/hertz/tutorials/toolkit/install.md +++ b/content/zh/docs/hertz/tutorials/toolkit/install.md @@ -1,5 +1,5 @@ --- -title: 'hz 安装' +title: "hz 安装" date: 2023-02-21 weight: 1 keywords: ["hz 安装"] @@ -13,15 +13,15 @@ hz 是 Hertz 框架提供的一个用于生成代码的命令行工具。目前 1. 确保 `GOPATH` 环境变量已经被正确的定义(例如 `export GOPATH=~/go`)并且将 `$GOPATH/bin` 添加到 `PATH` 环境变量之中(例如 `export PATH=$GOPATH/bin:$PATH`);请勿将 `GOPATH` 设置为当前用户没有读写权限的目录 2. 安装 hz: - ```bash - go install github.com/cloudwego/hertz/cmd/hz@latest - ``` + ```bash + go install github.com/cloudwego/hertz/cmd/hz@latest + ``` 3. 验证是否安装成功 `hz -v`, 如果显示如下版本的信息,则说明安装成功 - ```console - hz version v0.x.x - ``` + ```console + hz version v0.x.x + ``` **注意**,由于 hz 会为自身的二进制文件创建软链接,因此请确保 hz 的安装路径具有可写权限。 diff --git a/content/zh/docs/hertz/tutorials/toolkit/layout.md b/content/zh/docs/hertz/tutorials/toolkit/layout.md index 7a489579af..e62b6fd995 100644 --- a/content/zh/docs/hertz/tutorials/toolkit/layout.md +++ b/content/zh/docs/hertz/tutorials/toolkit/layout.md @@ -21,7 +21,7 @@ hz 生成的代码结构都类似,下面以 [hz 使用 (thrift)](/zh/docs/hert │ │ │ └── hello_service.go // handler 文件,用户在该文件里实现 IDL service 定义的方法,update 时会查找当前文件已有的 handler 并在尾部追加新的 handler │ │ └── ping.go // 默认携带的 ping handler,用于生成代码快速调试,无其他特殊含义 │ ├── model // idl 内容相关的生成代码 -│ │ └── hello // hello/example 对应 thrift idl 中定义的 namespace;而对于 protobuf idl,则是对应 go_package +│ │ └── hello // hello/example 对应 thrift idl 中定义的 namespace;而对于 protobuf idl,则是对应 go_package │ │ └── example │ │ └── hello.go // thriftgo 的产物,包含 hello.thrift 定义的内容的 go 代码,update 时会重新生成 │ └── router // idl 中定义的路由相关生成代码 @@ -38,7 +38,7 @@ hz 生成的代码结构都类似,下面以 [hz 使用 (thrift)](/zh/docs/hert ├── router_gen.go // hz 生成的路由注册代码,用于调用用户自定义的路由以及 hz 生成的路由 ├── .hz // hz 创建代码标志,无需改动 ├── build.sh // 程序编译脚本,Windows 下默认不生成,可直接使用 go build 命令编译程序 -├── script +├── script │ └── bootstrap.sh // 程序运行脚本,Windows 下默认不生成,可直接运行 main.go └── .gitignore ``` @@ -49,7 +49,7 @@ hz 生成的代码结构都类似,下面以 [hz 使用 (thrift)](/zh/docs/hert . ├── biz // business 层,存放业务逻辑相关流程 │ └── model // idl 内容相关的生成代码 -│ └── hello // hello/example 对应 thrift idl 中定义的 namespace;而对于 protobuf idl,则是对应 go_package +│ └── hello // hello/example 对应 thrift idl 中定义的 namespace;而对于 protobuf idl,则是对应 go_package │ └── example │ ├── hello.go // thriftgo 的产物,包含 hello.thrift 定义的内容的 go 代码,update 时会重新生成 │ └── hello_service // 基于 idl 生成的类似 RPC 形式的 http 请求一键调用代码,可与 hz 生成的 server 代码直接互通 diff --git a/content/zh/docs/hertz/tutorials/toolkit/more-feature/api_none.md b/content/zh/docs/hertz/tutorials/toolkit/more-feature/api_none.md index 7bd33f6e64..7ff8c14242 100644 --- a/content/zh/docs/hertz/tutorials/toolkit/more-feature/api_none.md +++ b/content/zh/docs/hertz/tutorials/toolkit/more-feature/api_none.md @@ -1,10 +1,11 @@ --- -title: 'api.none 注解说明' +title: "api.none 注解说明" date: 2023-04-23 weight: 5 keywords: ["api.none", "thrift", "protobuf"] description: "hz 提供的 api.none 注解说明。" --- + ## 介绍 hz 生成的代码会自动为结构体添加 go tag,从而方便进行参数绑定。 diff --git a/content/zh/docs/hertz/tutorials/toolkit/more-feature/client.md b/content/zh/docs/hertz/tutorials/toolkit/more-feature/client.md index 27a359166c..9dc2cc09a3 100644 --- a/content/zh/docs/hertz/tutorials/toolkit/more-feature/client.md +++ b/content/zh/docs/hertz/tutorials/toolkit/more-feature/client.md @@ -1,5 +1,5 @@ --- -title: 'hz client 代码生成' +title: "hz client 代码生成" date: 2023-02-20 weight: 4 keywords: ["hz client", "高级设置"] @@ -24,10 +24,10 @@ hz client 生成的代码结构可以参考 [hz client](/zh/docs/hertz/tutorials ### 定义 IDL ->IDL 的定义和语义与目前的定义完全相同,所以基本不用修改原先的 IDL 即可生成 client 代码。 +> IDL 的定义和语义与目前的定义完全相同,所以基本不用修改原先的 IDL 即可生成 client 代码。 ->但是为针对 client 的场景,增加了一种注解, ->api.base_domain:指定默认访问的请求 domain。 +> 但是为针对 client 的场景,增加了一种注解, +> api.base_domain:指定默认访问的请求 domain。 **注意**: 当使用 `api.any` 注解时,client 会自动生成 `post` 方法的 client 代码用于替换 `any`。 @@ -77,24 +77,23 @@ hz client --mod=a/b/c --idl=../idl/psm.thrift --model_dir=model --client_dir=her ### client 配置 -> > 以 thrift IDL 生成的代码为例 - ```go +```go func main() { - generatedClient, err := hello_service.NewHelloServiceClient("https://www.example.com"), + generatedClient, err := hello_service.NewHelloServiceClient("https://www.example.com"), hello_service.WithHertzClientOption() // 指定 client 配置 } ``` ### 请求级别的配置 -> + > 以 thrift IDL 生成的代码为例 ```go func main() { generatedClient, err := hello_service.NewHelloServiceClient( - "http://toutiao.hertz.testa", // 指定 psm 作为域名 + "http://toutiao.hertz.testa", // 指定 psm 作为域名 ) // 在发起调用的时候可指定请求级别的配置 resp, rawResp, err := generatedClient.QueryMethod( @@ -111,56 +110,56 @@ func main() { ``` ### 设置 client 中间件 -> + > 以 thrift IDL 生成的代码为例 ```go func main() { generatedClient, err := hello_service.NewHelloServiceClient( - "http://toutiao.hertz.testa", // 指定 psm 作为域名 - hello_service.WithHertzClientMiddleware(), // 指定 client 的中间件 + "http://toutiao.hertz.testa", // 指定 psm 作为域名 + hello_service.WithHertzClientMiddleware(), // 指定 client 的中间件 ) } ``` ### 设置全局 header -> ->以 thrift IDL 生成的代码为例 + +> 以 thrift IDL 生成的代码为例 有一些通用的 header 可能每次请求都需要携带,或者是一些不能定义到 IDL 中的 header,这时我们就可以通过 "WithHeader" 注入这些 header,使得每次发送请求都会携带这些 header。 ```go func main() { generatedClient, err := hello_service.NewHelloServiceClient( - "http://toutiao.hertz.testa", // 指定 psm 作为域名 - hello_service.WithHeader(), // 指定每次发送请求都需要携带的 header + "http://toutiao.hertz.testa", // 指定 psm 作为域名 + hello_service.WithHeader(), // 指定每次发送请求都需要携带的 header ) } ``` ### 配置 TLS -> + > 以 thrift IDL 生成的代码为例 Hertz client 的 TLS 走的是标准网络库,因此在使用生成的一键调用时需要配置为标准网络库。 ```go func main() { - generatedClient, err := hello_service.NewHelloServiceClient("https://www.example.com"), + generatedClient, err := hello_service.NewHelloServiceClient("https://www.example.com"), hello_service.WithHertzClientOption( - client.WithDialer(standard.NewDialer()), // 使用标准库 - client.WithTLSConfig(clientCfg), // TLS 配置 + client.WithDialer(standard.NewDialer()), // 使用标准库 + client.WithTLSConfig(clientCfg), // TLS 配置 ) } ``` ### 自定义 hertz client -> + > 以 thrift IDL 生成的代码为例 - ```go +```go func main() { - generatedClient, err := hello_service.NewHelloServiceClient("https://www.example.com"), + generatedClient, err := hello_service.NewHelloServiceClient("https://www.example.com"), hello_service.WithHertzClient() // 指定自定义 hertz client } ``` diff --git a/content/zh/docs/hertz/tutorials/toolkit/more-feature/plugin.md b/content/zh/docs/hertz/tutorials/toolkit/more-feature/plugin.md index 3060334647..40da34bfc4 100644 --- a/content/zh/docs/hertz/tutorials/toolkit/more-feature/plugin.md +++ b/content/zh/docs/hertz/tutorials/toolkit/more-feature/plugin.md @@ -1,5 +1,5 @@ --- -title: 'hz 接入第三方生成代码插件' +title: "hz 接入第三方生成代码插件" date: 2023-01-21 weight: 3 keywords: ["插件", "ThriftGo", "Protoc", "go_package"] @@ -55,9 +55,7 @@ hz new --idl={YOUR-IDL.proto} --protoc-plugins={PLUGIN_NAME}:{OPTION1,OPTION2}:{ 这里以使用 hz 时集成 `protoc-gen-openapi` 插件用来生成 openapi 3.0 文档为例。 - 安装:`go install github.com/google/gnostic/cmd/protoc-gen-openapi@latest` - - 定义 idl 的 go_package:"middleware/hertz/biz/model/psm" - - 使用:`hz new -I=idl --idl=idl/hello/hello.proto --protoc-plugins=openapi::./docs --mod=middleware/hertz` - 代码:[code](https://github.com/cloudwego/hertz-examples/tree/main/hz/plugin/proto) diff --git a/content/zh/docs/hertz/tutorials/toolkit/more-feature/template.md b/content/zh/docs/hertz/tutorials/toolkit/more-feature/template.md index 6fb1ad6a18..0c2fb392f4 100644 --- a/content/zh/docs/hertz/tutorials/toolkit/more-feature/template.md +++ b/content/zh/docs/hertz/tutorials/toolkit/more-feature/template.md @@ -15,14 +15,14 @@ Hertz 提供的命令行工具 (以下称为"hz") 支持自定义模板功能, ``` . -├── biz +├── biz │ ├── handler // biz/handler 为默认 handler_dir,可通过 --handler_dir 修改 │ │ ├── hello // handler 相关代码,与 idl 有关,package 模板生成 │ │ │ └── example -│ │ │ └── hello_service.go +│ │ │ └── hello_service.go │ │ └── ping.go // layout 模板生成 │ ├── model // biz/model 为默认 model_dir,可通过 --model_dir 修改 -│ │ └── hello +│ │ └── hello │ │ └── example │ │ └── hello.go // 由 hz 调用 thriftgo 生成,不涉及 layout 模板和 package 模板 │ │ └── hello_service // 调用 hz client 命令得到,与 idl 有关,package 模板生成 @@ -31,16 +31,16 @@ Hertz 提供的命令行工具 (以下称为"hz") 支持自定义模板功能, │ └── router // biz/router 为默认 router_dir,可通过 --router_dir 修改 │ ├── hello // router 相关代码,与 idl 有关,package 模板生成 │ │ └── example -│ │ ├── hello.go -│ │ └── middleware.go +│ │ ├── hello.go +│ │ └── middleware.go │ └── register.go // 未指定 idl 时,由 layout 模板生成;指定 idl 时,由 package 模板生成 ├── go.mod // go.mod 文件,layout 模板生成 ├── main.go // 程序入口,layout 模板生成 ├── router.go // 用户自定义除 idl 外的路由方法,layout 模板生成 └── router_gen.go // hz 生成的路由注册代码,用于调用用户自定义的路由以及 hz 生成的路由,layout 模板生成 -├── .hz +├── .hz ├── build.sh // 程序编译脚本,layout 模板生成 -├── script +├── script │ └── bootstrap.sh // 程序运行脚本,layout 模板生成 └── .gitignore // layout 模板生成 ``` @@ -84,7 +84,7 @@ layouts: delims: - "" - "" - body: "" + body: "" # 项目 main.go 文件 - path: main.go delims: @@ -229,7 +229,7 @@ layouts: CURDIR=$(cd $(dirname $0); pwd) BinaryName={{.ServiceName}} echo "$CURDIR/bin/${BinaryName}" - exec $CURDIR/bin/${BinaryName} + exec $CURDIR/bin/${BinaryName} ``` ### 模板渲染参数文件 @@ -240,19 +240,19 @@ hz 使用了 "json" 来指定渲染数据,包括全局的渲染参数和各个 #### 全局渲染参数 -全局渲染参数的 key 为 "*",hz 默认提供了如下五个全局渲染参数: +全局渲染参数的 key 为 "\*",hz 默认提供了如下五个全局渲染参数: -| 渲染参数名 | 默认值 | 说明 | -| :---- | :---- | :---- | -| GoModule | - | go module,可通过 --module 指定 | -| ServiceName | hertz_service | 服务名,可通过 --service 指定 | -| UseApacheThrift | - | idl 为 thrift 时为 true,否则为 false | -| HandlerPkg | handler | handler_dir 的最后一级路径,可通过 --handler_dir 修改 | -| RouterPkg | router | router_dir 的最后一级路径,可通过 --router_dir 修改 | +| 渲染参数名 | 默认值 | 说明 | +| :-------------- | :------------ | :---------------------------------------------------- | +| GoModule | - | go module,可通过 --module 指定 | +| ServiceName | hertz_service | 服务名,可通过 --service 指定 | +| UseApacheThrift | - | idl 为 thrift 时为 true,否则为 false | +| HandlerPkg | handler | handler_dir 的最后一级路径,可通过 --handler_dir 修改 | +| RouterPkg | router | router_dir 的最后一级路径,可通过 --router_dir 修改 | > 注意:除 UseApacheThrift 外,其它参数都可以通过命令行指定,此时若在自定义渲染参数文件中也指定了该参数,应保证两处参数的值一致,否则可能会出现问题。因此我们建议,在使用自定义模板时 ServiceName, HandlerPkg, RouterPkg 不需要在命令行中指定,在渲染参数文件中指出即可,GOPATH 外指定 go mod 时应保证两处的一致性。 -用户可以根据需求自定义全局渲染参数名和值,但需保证 key 为 "*"。 +用户可以根据需求自定义全局渲染参数名和值,但需保证 key 为 "\*"。 #### 文件渲染参数 @@ -378,8 +378,8 @@ layouts: # path 只表示 handler.go 的模板,具体的 handler 路径由默认路径和 handler_dir 决定 - path: handler.go delims: - - '{{' - - '}}' + - "{{" + - "}}" body: |- // Code generated by hertz generator. @@ -416,8 +416,8 @@ layouts: # path 只表示 router.go 的模板,具体的路径由默认路径和 router_dir 决定 - path: router.go delims: - - '{{' - - '}}' + - "{{" + - "}}" body: |- // Code generated by hertz generator. DO NOT EDIT. @@ -489,8 +489,8 @@ layouts: # path 只表示 middleware.go 的模板,middleware 的路径和 router.go 相同 - path: middleware.go delims: - - '{{' - - '}}' + - "{{" + - "}}" body: |- // Code generated by hertz generator. @@ -512,8 +512,8 @@ layouts: # path 只表示 client.go 的模板,仅当使用 hz new --client_dir 或 hz update --client_dir 时生成,路径由 out_dir 和 client_dir 决定 - path: client.go delims: - - '{{' - - '}}' + - "{{" + - "}}" body: |- // Code generated by hertz generator. @@ -541,8 +541,8 @@ layouts: # handler_single 表示单独的 handler 模板,用于 update 的时候更新每一个新增的 handler - path: handler_single.go delims: - - '{{' - - '}}' + - "{{" + - "}}" body: |+ {{.Comment}} func {{.Name}}(ctx context.Context, c *app.RequestContext) { @@ -563,8 +563,8 @@ layouts: # middleware_single 表示单独的 middleware 模板,用于 update 的时候更新每一个新增的 middleware_single - path: middleware_single.go delims: - - '{{' - - '}}' + - "{{" + - "}}" body: |+ func {{.MiddleWare}}Mw() []app.HandlerFunc { // your code... @@ -573,13 +573,13 @@ layouts: # hertz_client 由 hz client 命令生成,详细代码请参考 https://github.com/cloudwego/hertz/blob/develop/cmd/hz/generator/package_tpl.go#L271 - path: hertz_client.go delims: - - '{{' - - '}}' + - "{{" + - "}}" # idl_client 由 hz client 命令生成,详细代码请参考 https://github.com/cloudwego/hertz/blob/develop/cmd/hz/generator/package_tpl.go#L862 - path: idl_client.go delims: - - '{{' - - '}}' + - "{{" + - "}}" ``` ### 模板渲染参数 @@ -592,15 +592,15 @@ layouts: ```go type FilePathRenderInfo struct { - MasterIDLName string // master IDL name - GenPackage string // master IDL generate code package - HandlerDir string // handler generate dir - ModelDir string // model generate dir - RouterDir string // router generate dir - ProjectDir string // projectDir - GoModule string // go module - ServiceName string // service name, changed as services are traversed - MethodName string // method name, changed as methods are traversed + MasterIDLName string // master IDL name + GenPackage string // master IDL generate code package + HandlerDir string // handler generate dir + ModelDir string // model generate dir + RouterDir string // router generate dir + ProjectDir string // projectDir + GoModule string // go module + ServiceName string // service name, changed as services are traversed + MethodName string // method name, changed as methods are traversed HandlerGenPath string // "api.handler_path" value } ``` @@ -619,19 +619,19 @@ layouts: ```go type CustomizedFileForMethod struct { - *HttpMethod // 每个 method 定义的解析出来的具体信息 - FilePath string // 当循环生成 method 文件时,该文件路径 - FilePackage string // 当循环生成 method 文件时,该文件的 go package 名 + *HttpMethod // 每个 method 定义的解析出来的具体信息 + FilePath string // 当循环生成 method 文件时,该文件路径 + FilePackage string // 当循环生成 method 文件时,该文件的 go package 名 ServiceInfo *Service // 该 method 所属的 service 定义的信息 } - + type HttpMethod struct { Name string HTTPMethod string Comment string RequestTypeName string ReturnTypeName string - Path string // 请求路由 + Path string // 请求路由 Serializer string OutputDir string Models map[string]*model.Model @@ -642,9 +642,9 @@ layouts: ```go type CustomizedFileForService struct { - *Service // 该 service 的具体信息,包括 service 名字,servide 内定义的 method 的信息等 - FilePath string // 当循环生成 service 文件时,该文件路径 - FilePackage string // 当循环生成 service 文件时,该文件的 go package 名 + *Service // 该 service 的具体信息,包括 service 名字,servide 内定义的 method 的信息等 + FilePath string // 当循环生成 service 文件时,该文件路径 + FilePackage string // 当循环生成 service 文件时,该文件的 go package 名 IDLPackageInfo *IDLPackageRenderInfo // 该 service 所属的 IDL 定义的信息 } @@ -652,7 +652,7 @@ layouts: Name string Methods []*HttpMethod ClientMethods []*ClientMethod - Models []*model.Model // all dependency models + Models []*model.Model // all dependency models BaseDomain string // base domain for client code } ``` @@ -710,7 +710,7 @@ layouts: 下面给出一个简单的自定义 handler 模板的示例: #### example -> + > example:https://github.com/cloudwego/hertz-examples/tree/main/hz/template - 修改默认 handler 的内容 @@ -719,130 +719,130 @@ layouts: ```yaml layouts: - - path: handler.go - body: |- + - path: handler.go + body: |- + {{$OutDirs := GetUniqueHandlerOutDir .Methods}} + package {{.PackageName}} + import ( + "context" + + "github.com/cloudwego/hertz/pkg/app" + "github.com/cloudwego/hertz/pkg/protocol/consts" + {{- range $k, $v := .Imports}} + {{$k}} "{{$v.Package}}" + {{- end}} + {{- range $_, $OutDir := $OutDirs}} + {{if eq $OutDir "" -}} + "{{$.ProjPackage}}/biz/service" + {{- else -}} + "{{$.ProjPackage}}/biz/service/{{$OutDir}}" + {{- end -}} + {{- end}} + "{{$.ProjPackage}}/biz/utils" + ) + {{range $_, $MethodInfo := .Methods}} + {{$MethodInfo.Comment}} + func {{$MethodInfo.Name}}(ctx context.Context, c *app.RequestContext) { + var err error + {{if ne $MethodInfo.RequestTypeName "" -}} + var req {{$MethodInfo.RequestTypeName}} + err = c.BindAndValidate(&req) + if err != nil { + utils.SendErrResponse(ctx, c, consts.StatusOK, err) + return + } + {{end}} + {{if eq $MethodInfo.OutputDir "" -}} + resp,err := service.New{{$MethodInfo.Name}}Service(ctx, c).Run(&req) + if err != nil { + utils.SendErrResponse(ctx, c, consts.StatusOK, err) + return + } + {{else}} + resp,err := {{$MethodInfo.OutputDir}}.New{{$MethodInfo.Name}}Service(ctx, c).Run(&req) + if err != nil { + utils.SendErrResponse(ctx, c, consts.StatusOK, err) + return + } + {{end}} + utils.SendSuccessResponse(ctx, c, consts.StatusOK, resp) + } + {{end}} + update_behavior: + import_tpl: + - |- {{$OutDirs := GetUniqueHandlerOutDir .Methods}} - package {{.PackageName}} - import ( - "context" - - "github.com/cloudwego/hertz/pkg/app" - "github.com/cloudwego/hertz/pkg/protocol/consts" - {{- range $k, $v := .Imports}} - {{$k}} "{{$v.Package}}" - {{- end}} {{- range $_, $OutDir := $OutDirs}} {{if eq $OutDir "" -}} "{{$.ProjPackage}}/biz/service" {{- else -}} "{{$.ProjPackage}}/biz/service/{{$OutDir}}" - {{- end -}} - {{- end}} - "{{$.ProjPackage}}/biz/utils" - ) - {{range $_, $MethodInfo := .Methods}} - {{$MethodInfo.Comment}} - func {{$MethodInfo.Name}}(ctx context.Context, c *app.RequestContext) { - var err error - {{if ne $MethodInfo.RequestTypeName "" -}} - var req {{$MethodInfo.RequestTypeName}} - err = c.BindAndValidate(&req) - if err != nil { - utils.SendErrResponse(ctx, c, consts.StatusOK, err) - return - } - {{end}} - {{if eq $MethodInfo.OutputDir "" -}} - resp,err := service.New{{$MethodInfo.Name}}Service(ctx, c).Run(&req) - if err != nil { - utils.SendErrResponse(ctx, c, consts.StatusOK, err) - return - } - {{else}} - resp,err := {{$MethodInfo.OutputDir}}.New{{$MethodInfo.Name}}Service(ctx, c).Run(&req) - if err != nil { - utils.SendErrResponse(ctx, c, consts.StatusOK, err) - return - } {{end}} - utils.SendSuccessResponse(ctx, c, consts.StatusOK, resp) - } - {{end}} - update_behavior: - import_tpl: - - |- - {{$OutDirs := GetUniqueHandlerOutDir .Methods}} - {{- range $_, $OutDir := $OutDirs}} - {{if eq $OutDir "" -}} - "{{$.ProjPackage}}/biz/service" - {{- else -}} - "{{$.ProjPackage}}/biz/service/{{$OutDir}}" - {{end}} - {{- end}} - - - path: handler_single.go - body: |+ - {{.Comment}} - func {{.Name}}(ctx context.Context, c *app.RequestContext) { - var err error - {{if ne .RequestTypeName "" -}} - var req {{.RequestTypeName}} - err = c.BindAndValidate(&req) - if err != nil { + {{- end}} + + - path: handler_single.go + body: |+ + {{.Comment}} + func {{.Name}}(ctx context.Context, c *app.RequestContext) { + var err error + {{if ne .RequestTypeName "" -}} + var req {{.RequestTypeName}} + err = c.BindAndValidate(&req) + if err != nil { + utils.SendErrResponse(ctx, c, consts.StatusOK, err) + return + } + {{end}} + {{if eq .OutputDir "" -}} + resp,err := service.New{{.Name}}Service(ctx, c).Run(&req) + {{else}} + resp,err := {{.OutputDir}}.New{{.Name}}Service(ctx, c).Run(&req) + {{end}} + if err != nil { utils.SendErrResponse(ctx, c, consts.StatusOK, err) return - } - {{end}} - {{if eq .OutputDir "" -}} - resp,err := service.New{{.Name}}Service(ctx, c).Run(&req) - {{else}} - resp,err := {{.OutputDir}}.New{{.Name}}Service(ctx, c).Run(&req) - {{end}} - if err != nil { - utils.SendErrResponse(ctx, c, consts.StatusOK, err) - return - } - utils.SendSuccessResponse(ctx, c, consts.StatusOK, resp) - }= - - path: "{{.HandlerDir}}/{{.GenPackage}}/{{ToSnakeCase .ServiceName}}_test.go" - loop_service: true - update_behavior: - type: "append" - append_key: "method" - insert_key: "Test{{$.Name}}" - append_tpl: |- - func Test{{.Name}}(t *testing.T) { - h := server.Default() - h.{{.HTTPMethod}}("{{.Path}}", {{.Name}}) - w := ut.PerformRequest(h.Engine, "{{.HTTPMethod}}", "{{.Path}}", &ut.Body{Body: bytes.NewBufferString(""), Len: 1}, - ut.Header{}) - resp := w.Result() - assert.DeepEqual(t, 201, resp.StatusCode()) - assert.DeepEqual(t, "", string(resp.Body())) - // todo edit your unit test. - } - body: |- - package {{.FilePackage}} - import ( - "bytes" - "testing" - - "github.com/cloudwego/hertz/pkg/app/server" - "github.com/cloudwego/hertz/pkg/common/test/assert" - "github.com/cloudwego/hertz/pkg/common/ut" - ) - {{range $_, $MethodInfo := $.Methods}} - func Test{{$MethodInfo.Name}}(t *testing.T) { - h := server.Default() - h.{{$MethodInfo.HTTPMethod}}("{{$MethodInfo.Path}}", {{$MethodInfo.Name}}) - w := ut.PerformRequest(h.Engine, "{{$MethodInfo.HTTPMethod}}", "{{$MethodInfo.Path}}", &ut.Body{Body: bytes.NewBufferString(""), Len: 1}, - ut.Header{}) - resp := w.Result() - assert.DeepEqual(t, 201, resp.StatusCode()) - assert.DeepEqual(t, "", string(resp.Body())) - // todo edit your unit test. - } - {{end}} + } + utils.SendSuccessResponse(ctx, c, consts.StatusOK, resp) + }= + - path: "{{.HandlerDir}}/{{.GenPackage}}/{{ToSnakeCase .ServiceName}}_test.go" + loop_service: true + update_behavior: + type: "append" + append_key: "method" + insert_key: "Test{{$.Name}}" + append_tpl: |- + func Test{{.Name}}(t *testing.T) { + h := server.Default() + h.{{.HTTPMethod}}("{{.Path}}", {{.Name}}) + w := ut.PerformRequest(h.Engine, "{{.HTTPMethod}}", "{{.Path}}", &ut.Body{Body: bytes.NewBufferString(""), Len: 1}, + ut.Header{}) + resp := w.Result() + assert.DeepEqual(t, 201, resp.StatusCode()) + assert.DeepEqual(t, "", string(resp.Body())) + // todo edit your unit test. + } + body: |- + package {{.FilePackage}} + import ( + "bytes" + "testing" + + "github.com/cloudwego/hertz/pkg/app/server" + "github.com/cloudwego/hertz/pkg/common/test/assert" + "github.com/cloudwego/hertz/pkg/common/ut" + ) + {{range $_, $MethodInfo := $.Methods}} + func Test{{$MethodInfo.Name}}(t *testing.T) { + h := server.Default() + h.{{$MethodInfo.HTTPMethod}}("{{$MethodInfo.Path}}", {{$MethodInfo.Name}}) + w := ut.PerformRequest(h.Engine, "{{$MethodInfo.HTTPMethod}}", "{{$MethodInfo.Path}}", &ut.Body{Body: bytes.NewBufferString(""), Len: 1}, + ut.Header{}) + resp := w.Result() + assert.DeepEqual(t, 201, resp.StatusCode()) + assert.DeepEqual(t, "", string(resp.Body())) + // todo edit your unit test. + } + {{end}} ``` ## MVC 模板实践 diff --git a/content/zh/docs/hertz/tutorials/toolkit/usage-protobuf.md b/content/zh/docs/hertz/tutorials/toolkit/usage-protobuf.md index cc84d268af..0a6e946555 100644 --- a/content/zh/docs/hertz/tutorials/toolkit/usage-protobuf.md +++ b/content/zh/docs/hertz/tutorials/toolkit/usage-protobuf.md @@ -4,7 +4,7 @@ date: 2023-02-21 weight: 4 keywords: ["hz 使用 (protobuf)", "protobuf", "new", "update"] description: > - "hz 使用 (protobuf)。" + "hz 使用 (protobuf)。" --- ## 基于 protobuf IDL 创建项目 @@ -41,7 +41,7 @@ description: > optional string js_conv = 50109; optional string file_name = 50110; optional string none = 50111; - + // 50131~50160 used to extend field option by hz optional string form_compatible = 50131; optional string js_conv_compatible = 50132; @@ -49,7 +49,7 @@ description: > optional string none_compatible = 50134; // 50135 is reserved to vt_compatible // optional FieldRules vt_compatible = 50135; - + optional string go_tag = 51001; } @@ -71,7 +71,7 @@ description: > optional string param = 50307; // Whether client requests take public parameters optional string baseurl = 50308; // Baseurl used in ttnet routing optional string handler_path = 50309; // handler_path specifies the path to generate the method - + // 50331~50360 used to extend method option by hz optional string handler_path_compatible = 50331; // handler_path specifies the path to generate the method } @@ -91,7 +91,7 @@ description: > extend google.protobuf.MessageOptions { // optional FieldRules msg_vt = 50111; - + optional string reserve = 50830; // 550831 is reserved to msg_vt_compatible // optional FieldRules msg_vt_compatible = 50831; diff --git a/content/zh/docs/hertz/tutorials/toolkit/usage-thrift.md b/content/zh/docs/hertz/tutorials/toolkit/usage-thrift.md index 3d7af7c05e..7b3bd13a64 100644 --- a/content/zh/docs/hertz/tutorials/toolkit/usage-thrift.md +++ b/content/zh/docs/hertz/tutorials/toolkit/usage-thrift.md @@ -159,6 +159,7 @@ description: "hz 使用 (thrift)。" ``` **注意**: + 1. 与 protobuf 不同,在编写 update 命令时,只需要指定定义 `service` 的 IDL 文件,hz 会自动将该文件的所有依赖文件都进行生成。 3. 可以看到 diff --git a/content/zh/docs/kitex/Best Practice/Integration Testing/_index.md b/content/zh/docs/kitex/Best Practice/Integration Testing/_index.md index 0fc77ac529..746114ce62 100644 --- a/content/zh/docs/kitex/Best Practice/Integration Testing/_index.md +++ b/content/zh/docs/kitex/Best Practice/Integration Testing/_index.md @@ -5,4 +5,3 @@ weight: 5 date: 2024-02-18 description: "介绍如何 mock client 调用以及高效 debug 思路。" --- - diff --git a/content/zh/docs/kitex/Best Practice/Integration Testing/debug_efficiently.md b/content/zh/docs/kitex/Best Practice/Integration Testing/debug_efficiently.md index e273d8ce44..e23ea162e1 100644 --- a/content/zh/docs/kitex/Best Practice/Integration Testing/debug_efficiently.md +++ b/content/zh/docs/kitex/Best Practice/Integration Testing/debug_efficiently.md @@ -3,7 +3,7 @@ title: "高效 Debug" linkTitle: "高效 Debug" weight: 2 date: 2024-02-18 -description: "通过模仿真实错误示例,描述不同现象背后可能是什么样的原因类型,并提供分析原因的方法。" +description: "通过模仿真实错误示例,描述不同现象背后可能是什么样的原因类型,并提供分析原因的方法。" --- ## 排查 Panic 原因 @@ -66,9 +66,9 @@ created by testing.(*T).Run 1. 找到 panic 原因 -​ 首先我们需要知道导致我们 Panic 的真正原因是什么,可以在完整的 panic stack 最上面一行找到。 +​ 首先我们需要知道导致我们 Panic 的真正原因是什么,可以在完整的 panic stack 最上面一行找到。 -​ 如这里就是 **`panic: runtime error: slice bounds out of range [:5] with capacity 0 [recovered]`**。 +​ 如这里就是 **`panic: runtime error: slice bounds out of range [:5] with capacity 0 [recovered]`**。 2. 找到原始 panic 位置 @@ -94,7 +94,7 @@ created by testing.(*T).Run panic: runtime error: slice bounds out of range [:5] with capacity 0 [recovered] panic: runtime error: slice bounds out of range [:5] with capacity 0 [recovered] panic: runtime error: slice bounds out of range [:5] with capacity 0 - + goroutine 18 [running]: testing.tRunner.func1.2(0x113c7c0, 0xc00011c000) /usr/local/go/src/testing/testing.go:1144 +0x332 @@ -207,7 +207,7 @@ type Response struct { //go:noinline func RPCCall(req *Request) *Response { resp := &Response{Data: []byte("hello")} - if req.Id%100 == 0 { // Logic Bug + if req.Id%100 == 0 { // Logic Bug go func() { resp.Data = []byte("world") }() @@ -255,7 +255,7 @@ ulimit -c unlimited # 对于由公司统一控制的机器来说,一般这个目录会被指定到 /opt/tiger/cores 。 cat /proc/sys/kernel/core_pattern -# 指示 Go Runtime 处理 coredump +# 指示 Go Runtime 处理 coredump GOTRACEBACK=crash ./{bin_exec} ``` @@ -447,7 +447,7 @@ error(*main.MyError) nil 通过阅读 Go 的源码和文档,我们可以知道在 Go 中,一个有具体类型但是值为 nil 的 interface 对象,并不是等于 nil 的。 -接下来的问题是,在什么情况下,会导致 err 有类型,但是值为 nil 呢?我们可以在代码中搜索所有可能声明 var err *MyError 的地方,找到如下位置: +接下来的问题是,在什么情况下,会导致 err 有类型,但是值为 nil 呢?我们可以在代码中搜索所有可能声明 var err \*MyError 的地方,找到如下位置: ```go func Buy(id int) (*Item, error) { @@ -486,13 +486,13 @@ Frame 12: /home/wangzhuowei/code/chore/main.go:41 (PC: 491101) 39: if item == nil && err != nil { 40: if merr, ok := err.(*MyError); ok { => 41: log.Printf("Buy[%d] get error: %v", id, merr.Error()) - 42: } + 42: } (dlv) print id 57 ``` 由于这里的 `Handler` 函数与上层调用函数唯一的联系只有参数 id ,所以我们只需要打印它的值即可。可以看到,在外层 frame 13 中,id 的值为 58,而内层 frame 12 中,它的值为 57,所以我们可以知道,在开始 Handler 调用的时候,id 值为 57 ,而发生 panic 的时候,id 值已经被修改为 58 了。而这是不符合我们预期的,因为这证明了在调用 Handler 函数前,很可能 id 也被修改了,从而使得内层 Buy 函数出现访问到了已经被访问并删除的对象。进而出现上面最终的错误。 - 当找到这个线索后,我们再根据线索去找会修改 id 值的代码段,便可以清晰地找到真正的问题所在了。即,在 50 行修改了此时正被其他 Goroutine 对象持有的 id 对象。 +当找到这个线索后,我们再根据线索去找会修改 id 值的代码段,便可以清晰地找到真正的问题所在了。即,在 50 行修改了此时正被其他 Goroutine 对象持有的 id 对象。 ```go func main() { @@ -582,6 +582,6 @@ func AddSSH(data *SSHData) { } ``` -该函数理论上,对于每一个 UserId,会在 Map 里存储 6 字节的对象。而由于 main 函数每秒会调用 `AddSSH` 1000 次,即每秒泄漏 6KB 的内存。即便如此,我们就算程序运行一小时,也无非泄漏 6 * 60 * 60 = 21600KB = 21MB 的数据,不至于一分钟内就泄漏了 60MB。 +该函数理论上,对于每一个 UserId,会在 Map 里存储 6 字节的对象。而由于 main 函数每秒会调用 `AddSSH` 1000 次,即每秒泄漏 6KB 的内存。即便如此,我们就算程序运行一小时,也无非泄漏 6 _ 60 _ 60 = 21600KB = 21MB 的数据,不至于一分钟内就泄漏了 60MB。 但如果再进一步去细看 `append` 函数的细节,我们会发现它最终返回的那个切片对象,底层数组的引用,依然还是原始 `randBytes` 函数所创建的那个,而切片的部分引用,依然会导致原始对象不能够被完全释放。 diff --git a/content/zh/docs/kitex/Best Practice/Integration Testing/mock_client.md b/content/zh/docs/kitex/Best Practice/Integration Testing/mock_client.md index 1147b343f0..6f9e745476 100644 --- a/content/zh/docs/kitex/Best Practice/Integration Testing/mock_client.md +++ b/content/zh/docs/kitex/Best Practice/Integration Testing/mock_client.md @@ -40,7 +40,7 @@ func MockHello(ctx context.Context, req *hello.MyReq, callOptions ...callopt.Opt // TestClient 测试 mock 函数 func TestClient(t *testing.T) { - + ctrl := gomock.NewController(t) defer ctrl.Finish() @@ -49,7 +49,7 @@ func TestClient(t *testing.T) { // 添加 mock 函数 client.EXPECT().Hello(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(MockHello).AnyTimes() - + // 发起 mock call resp, err := client.Hello(context.Background(), &hello.MyReq{Name: "bd"}) if err == nil { diff --git a/content/zh/docs/kitex/Best Practice/error_handle.md b/content/zh/docs/kitex/Best Practice/error_handle.md index 24f0b3ff93..34e3fd76c8 100644 --- a/content/zh/docs/kitex/Best Practice/error_handle.md +++ b/content/zh/docs/kitex/Best Practice/error_handle.md @@ -31,9 +31,9 @@ kitex 的关于错误的定义在以下包目录中: `kitex/pkg/kerrors`: -○ kitex 核心所依赖的错误定义,支持 `errors.Is` 和 `errors.Unwrap` +○ kitex 核心所依赖的错误定义,支持 `errors.Is` 和 `errors.Unwrap` -○ kitex 定义的 `basic error types` 可以用 `WithCause` 来添加详细原因。 +○ kitex 定义的 `basic error types` 可以用 `WithCause` 来添加详细原因。 ### 判断是否 Kitex 内部错误 @@ -106,9 +106,9 @@ if de.ErrorType() == kerrors.ErrInternalException {} // 返回 true 关于调用端上报的错误码 -○ < v0.2.0:调用端上报错误码 119 +○ < v0.2.0:调用端上报错误码 119 -○ >= v0.2.0:上报下面对应的错误码 +○ >= v0.2.0:上报下面对应的错误码 (该变更是为了能统一服务端返回的错误码处理,的确存在服务端会透传一些错误码需要被客户端感知,统一为 119 存在不合理性) diff --git a/content/zh/docs/kitex/Best Practice/usage_attention.md b/content/zh/docs/kitex/Best Practice/usage_attention.md index 3d584fd50c..1b7314dc2b 100644 --- a/content/zh/docs/kitex/Best Practice/usage_attention.md +++ b/content/zh/docs/kitex/Best Practice/usage_attention.md @@ -20,18 +20,17 @@ Kitex 的 RPCInfo 的生命周期默认是从请求开始到请求返回(性 "github.com/cloudwego/kitex/pkg/rpcinfo" ) // this creates a read-only copy of `ri` and attaches it to the new context - ctx2 := rpcinfo.FreezeRPCInfo(ctx) + ctx2 := rpcinfo.FreezeRPCInfo(ctx) go func(ctx context.Context) { // ... ri := rpcinfo.GetRPCInfo(ctx) // OK - + //... }(ctx2) ``` - 配置环境变量 `KITEX_DISABLE_RPCINFO_POOL=true`,禁用 RPCInfo 回收 (支持版本: v0.8.1) - ## 勿**每个请求创建一个** kitex client Kitex client 对象管理着远程配置、服务发现的缓存、连接池等与 Service 相关的资源,会对应创建若干 goroutine 以完成各种异步更新工作。如果频繁创建 kitex client,会导致服务的 CPU 会陡然升高,RPC 调用、 服务发现、远程配置拉取频繁超时,以及 goroutine 数目大涨。 diff --git a/content/zh/docs/kitex/FAQ/_index.md b/content/zh/docs/kitex/FAQ/_index.md index 4fd7f402c5..8a7dc63c41 100644 --- a/content/zh/docs/kitex/FAQ/_index.md +++ b/content/zh/docs/kitex/FAQ/_index.md @@ -10,42 +10,54 @@ description: "Kitex 常见问题解答。" ## Kitex 框架 **Q1: 支持 Windows 吗?** -* 是的。Kitex 在 v0.4.0 版本已支持在 Windows 环境下编译运行了。代码生成工具在 v0.5.2 也支持了 Windows 环境。 + +- 是的。Kitex 在 v0.4.0 版本已支持在 Windows 环境下编译运行了。代码生成工具在 v0.5.2 也支持了 Windows 环境。 **Q2: 是否支持 HTTP?** -* 目前 Kitex 没有支持 HTTP 请求,如果是 API 网关场景,针对 Thrift 提供了 [HTTP 映射的泛化调用](/zh/docs/kitex/tutorials/advanced-feature/generic-call/),Kitex 会将 HTTP 请求做 Thrift 编码发给服务端。 -* HTTP 可以使用 CloudWeGo 开源的 HTTP 框架 [Hertz](/zh/docs/hertz/)。 + +- 目前 Kitex 没有支持 HTTP 请求,如果是 API 网关场景,针对 Thrift 提供了 [HTTP 映射的泛化调用](/zh/docs/kitex/tutorials/advanced-feature/generic-call/),Kitex 会将 HTTP 请求做 Thrift 编码发给服务端。 +- HTTP 可以使用 CloudWeGo 开源的 HTTP 框架 [Hertz](/zh/docs/hertz/)。 **Q3: 如何配置开启连接多路复用?** -* 如果使用 Thrift 或 Kitex Protobuf ,开启连接多路复用:服务端配置 WithMuxTransport(),调用端配置 WithMuxConnection(1)。 -* 如果使用 gRPC, 默认是连接多路复用。 + +- 如果使用 Thrift 或 Kitex Protobuf ,开启连接多路复用:服务端配置 WithMuxTransport(),调用端配置 WithMuxConnection(1)。 +- 如果使用 gRPC, 默认是连接多路复用。 **Q4: 本地直连场景下,配置长连接池为什么没有生效?** -* 本地测试 ip 需要改成 127.0.0.1,如 client.WithHostPorts("127.0.0.1:8888")。 + +- 本地测试 ip 需要改成 127.0.0.1,如 client.WithHostPorts("127.0.0.1:8888")。 **Q5: Kitex Protobuf 和 gRPC 协议区别** -* Kitex Protobuf 是 Kitex 自定义的 Protobuf 消息协议,协议格式类似 Thrift。 -* gRPC 是对 gRPC 消息协议的支持,可以与 gRPC 框架互通。 + +- Kitex Protobuf 是 Kitex 自定义的 Protobuf 消息协议,协议格式类似 Thrift。 +- gRPC 是对 gRPC 消息协议的支持,可以与 gRPC 框架互通。 **Q6: 出现 Thrift 接口编译问题,如 not enough arguments in call to iprot.ReadStructBegin** -* Kitex 依赖 Thrift v0.13,因为Apache Thrift v0.14 接口有 breaking change,无法直接升级。出现该问题是拉到了新版本的 Thrift,升级版本时建议不使用 -u 参数,可以执行命令固定版本 `go mod edit -replace github.com/apache/thrift=github.com/apache/thrift@v0.13.0` + +- Kitex 依赖 Thrift v0.13,因为Apache Thrift v0.14 接口有 breaking change,无法直接升级。出现该问题是拉到了新版本的 Thrift,升级版本时建议不使用 -u 参数,可以执行命令固定版本 `go mod edit -replace github.com/apache/thrift=github.com/apache/thrift@v0.13.0` ## Kitex 代码生成工具 **Q1: 安装代码生成工具,出现了 'not enough arguments' 问题** -* 请开启go mod:GO111MODULE=on go get github.com/cloudwego/kitex/tool/cmd/kitex@latest + +- 请开启go mod:GO111MODULE=on go get github.com/cloudwego/kitex/tool/cmd/kitex@latest **Q2: 为什么 IDL 里的 set 生成了 slice?** -* Apache Thrift 官方从 JSON 序列化的角度考虑,v0.11.0 开始,[将 set 的生成类型从 map 改为了 slice](https://issues.apache.org/jira/browse/THRIFT-4011),Kitex 从兼容性角度考虑,对齐了该行为。 + +- Apache Thrift 官方从 JSON 序列化的角度考虑,v0.11.0 开始,[将 set 的生成类型从 map 改为了 slice](https://issues.apache.org/jira/browse/THRIFT-4011),Kitex 从兼容性角度考虑,对齐了该行为。 **Q3: 为什么有些字段名字后面多了条下划线?** -* Thrift 的官方实现为了避免命名冲突,限制了以「Result」和「Args」结尾的标识符。 官方 Thrift 的冲突规避策略:当 Thrift 文件中的类型名、Service 名和方法名,以 New 开头 或者 以 Result 或者 以 Args 结尾时,Thrift 会自动在名字末尾添加下划线。参考 https://jira.apache.org/jira/browse/THRIFT-4410,Kitex 使用了 Thriftgo 进行代码生成,Thriftgo 为了尽可能和官方实现保持一致,采取了类似的策略。 + +- Thrift 的官方实现为了避免命名冲突,限制了以「Result」和「Args」结尾的标识符。 官方 Thrift 的冲突规避策略:当 Thrift 文件中的类型名、Service 名和方法名,以 New 开头 或者 以 Result 或者 以 Args 结尾时,Thrift 会自动在名字末尾添加下划线。参考 https://jira.apache.org/jira/browse/THRIFT-4410,Kitex 使用了 Thriftgo 进行代码生成,Thriftgo 为了尽可能和官方实现保持一致,采取了类似的策略。 **Q4: 新增接口重新生成代码,是否会覆盖handler.go** -* kitex_gen/ 下的生成代码会重新生成覆盖,但服务端的 handler.go 不会覆盖,只会新增对应方法。 + +- kitex_gen/ 下的生成代码会重新生成覆盖,但服务端的 handler.go 不会覆盖,只会新增对应方法。 **Q5: 请问目前代码生成工具中的模板是否支持用户自定义?** -* 目前没有支持自定义模板的打算,因为传参设计会复杂很多。现在的插件机制完全可以实现任意等价的功能 + +- 目前没有支持自定义模板的打算,因为传参设计会复杂很多。现在的插件机制完全可以实现任意等价的功能 **Q6: 代码生成工具中的 –type 是否可以通过 IDL 文件扩展名自动确定?** -* Kitex 在 v0.4.0 版本已支持根据文件后缀生成代码,无需再添加 -type 参数。 + +- Kitex 在 v0.4.0 版本已支持根据文件后缀生成代码,无需再添加 -type 参数。 diff --git a/content/zh/docs/kitex/Getting started/examples.md b/content/zh/docs/kitex/Getting started/examples.md index 6a65377c78..7cb119ca2d 100644 --- a/content/zh/docs/kitex/Getting started/examples.md +++ b/content/zh/docs/kitex/Getting started/examples.md @@ -5,7 +5,6 @@ weight: 5 date: 2024-01-18 keywords: ["Kitex", "Golang", "Go", "示例代码"] description: "Kitex 使用示例代码" - --- ## 如何运行 diff --git a/content/zh/docs/kitex/Getting started/pre-knowledge.md b/content/zh/docs/kitex/Getting started/pre-knowledge.md index 0d7cadae83..8f5ba4c3af 100644 --- a/content/zh/docs/kitex/Getting started/pre-knowledge.md +++ b/content/zh/docs/kitex/Getting started/pre-knowledge.md @@ -5,7 +5,6 @@ weight: 1 date: 2024-01-18 keywords: ["Kitex", "Golang", "Go", "前置知识"] description: "Kitex 开发前置知识" - --- ## RPC @@ -37,7 +36,7 @@ description: "Kitex 开发前置知识" 11. (客户端)反序列化出结果 12. (客户端)得到调用的结果 -其中步骤 2 中包含的流程称为「**服务治理**」,通常包括并不限于服务发现、负载均衡、ACL、熔断、限流等等功能。这些功能是由其他组件提供的,并不是 Thrift 框架所具有的功能。 +其中步骤 2 中包含的流程称为「**服务治理**」,通常包括并不限于服务发现、负载均衡、ACL、熔断、限流等等功能。这些功能是由其他组件提供的,并不是 Thrift 框架所具有的功能。 ### RPC 服务开发流程 @@ -55,7 +54,7 @@ description: "Kitex 开发前置知识" 如果我们要使用 RPC 进行调用,就需要知道对方的接口是什么,需要传什么参数,同时也需要知道返回值是什么样的,就好比两个人之间交流,需要保证在说的是同一个语言、同一件事。IDL 就是为了解决这样的问题,通过 IDL 来约定双方的协议,就像在写代码的时候需要调用某个函数,我们需要知道 `签名`一样。 -对于 RPC 框架,IDL 不仅作为接口描述语言,还会根据 IDL 文件生成指定语言的接口定义模块,这样极大简化了开发工作。服务提供方(服务端)需要做的变为 编写 IDL -> 使用代码生成工具生成代码 -> 实现接口;服务调用方(客户端)只需根据服务提供方(服务端)提供的 IDL 生成代码后进行调用。这当中还有服务发现、负载均衡等问题,但不属于 IDL 范畴,故不展开介绍。 +对于 RPC 框架,IDL 不仅作为接口描述语言,还会根据 IDL 文件生成指定语言的接口定义模块,这样极大简化了开发工作。服务提供方(服务端)需要做的变为 编写 IDL -> 使用代码生成工具生成代码 -> 实现接口;服务调用方(客户端)只需根据服务提供方(服务端)提供的 IDL 生成代码后进行调用。这当中还有服务发现、负载均衡等问题,但不属于 IDL 范畴,故不展开介绍。 Kitex 默认支持 `thrift` 和 `proto3` 两种 IDL。本文简单介绍 Thrift IDL 语法,proto3 语法可参考:[Language Guide(proto3)](https://developers.google.com/protocol-buffers/docs/proto3) @@ -96,7 +95,7 @@ Thrift 提供的容器是强类型容器,映射到大多数编程语言中常 Thrift 支持类似 C/C++ 的类型定义 ```Thrift -typedef i32 MyInteger +typedef i32 MyInteger typedef Tweet ReTweet ``` @@ -112,11 +111,11 @@ Thrift 提供了枚举类型 - 不支持嵌套的 enum ```Thrift -enum TweetType { - TWEET, // - RETWEET = 2, // +enum TweetType { + TWEET, // + RETWEET = 2, // DM = 0xa, - REPLY + REPLY } ``` @@ -126,7 +125,7 @@ Thrift 支持 c风格的多行注释 和 c++/Java 风格的单行注释 ```Thrift /* -* This is a multi-line comment. +* This is a multi-line comment. * Just like in C. */ @@ -154,7 +153,7 @@ namespace go com.example.project ```Thrift include "tweet.thrift" ... -struct TweetSearchResult { +struct TweetSearchResult { 1: list tweets; } ``` @@ -167,7 +166,7 @@ Thrift 内定义常量的方式如下: const i32 INT_CONST = 1234; const map MAP_CONST = { - "hello": "world", + "hello": "world", "goodnight": "moon" } ``` @@ -188,14 +187,14 @@ Struct 由不同的 fields 构成,其中每个 **field** 有唯一的整型 ** ```Thrift struct Location { - 1: required double latitude; - 2: required double longitude; + 1: required double latitude; + 2: required double longitude; } -struct Tweet { +struct Tweet { 1: required i32 userId; 2: required string userName; - 3: required string text; + 3: required string text; 4: optional Location loc; // Struct的定义内可以包含其他 Struct 16: optional string language = "english" // 可设置默认值 } @@ -220,17 +219,17 @@ Thrift 内的 service 定义在语义上和 oop 内的接口是相同的。代 > oneway 本身不具有可靠性,且在处理上比较特殊会带来一些隐患,不建议使用 ```Thrift -service Twitter { - // A method definition looks like C code. It has a return type, arguments, - // and optionally a list of exceptions that it may throw. Note that argument - // lists and exception list are specified using the exact same syntax as +service Twitter { + // A method definition looks like C code. It has a return type, arguments, + // and optionally a list of exceptions that it may throw. Note that argument + // lists and exception list are specified using the exact same syntax as // field lists in structs. - void ping(); // 1 - bool postTweet(1:Tweet tweet); // 2 + void ping(); // 1 + bool postTweet(1:Tweet tweet); // 2 TweetSearchResult searchTweets(1:string query); // 3 - - // The 'oneway' modifier indicates that the client only makes a request and does not wait for any response at all. Oneway methods MUST be void. + + // The 'oneway' modifier indicates that the client only makes a request and does not wait for any response at all. Oneway methods MUST be void. oneway void zip() // 4 } ``` diff --git a/content/zh/docs/kitex/Getting started/prerequisite.md b/content/zh/docs/kitex/Getting started/prerequisite.md index 0bf5459168..9a1c774575 100644 --- a/content/zh/docs/kitex/Getting started/prerequisite.md +++ b/content/zh/docs/kitex/Getting started/prerequisite.md @@ -28,6 +28,7 @@ $ go version // output go version go1.19.12 darwin/arm64 ``` + 安装成功后,你可能需要设置一下国内代理: ```bash @@ -74,4 +75,4 @@ go install github.com/cloudwego/kitex/tool/cmd/kitex@latest ```bash $ kitex --version vx.x.x -``` \ No newline at end of file +``` diff --git a/content/zh/docs/kitex/Getting started/quick_start.md b/content/zh/docs/kitex/Getting started/quick_start.md index c5fd3c32a1..976861f4fa 100644 --- a/content/zh/docs/kitex/Getting started/quick_start.md +++ b/content/zh/docs/kitex/Getting started/quick_start.md @@ -5,7 +5,6 @@ weight: 3 date: 2024-01-18 keywords: ["Kitex", "Golang", "Go", "基础示例"] description: "Kitex 基础示例" - --- 开始此章节前,确保你已经了解**前置知识**并完成了**环境准备**。 @@ -29,7 +28,7 @@ description: "Kitex 基础示例" ```shell go run . - + // 输出类似日志代表运行成功 2024/01/18 20:35:08.857352 server.go:83: [Info] KITEX: server listen at addr=[::]:8888 ``` @@ -38,7 +37,7 @@ description: "Kitex 基础示例" ```shell go run ./client - + // 每隔一秒输出类似日志代表运行成功 2024/01/18 20:39:59 Response({Message:my request}) 2024/01/18 20:40:00 Response({Message:my request}) @@ -63,7 +62,7 @@ description: "Kitex 基础示例" ```shell docker run --network host kitex-examples ./hello-server - + // 输出类似日志代表运行成功 2024/01/18 12:47:34.712415 server.go:83: [Info] KITEX: server listen at addr=[::]:8888 ``` @@ -72,7 +71,7 @@ description: "Kitex 基础示例" ```shell docker run --network host kitex-examples ./hello-client - + // 每隔一秒输出类似日志代表运行成功 2024/01/18 12:48:20 Response({Message:my request}) 2024/01/18 12:48:21 Response({Message:my request}) @@ -225,4 +224,3 @@ for { ``` 恭喜你,完成了快速上手的所有内容! - diff --git a/content/zh/docs/kitex/Getting started/tutorial.md b/content/zh/docs/kitex/Getting started/tutorial.md index 39822a1f5c..8e0e4ff0f9 100644 --- a/content/zh/docs/kitex/Getting started/tutorial.md +++ b/content/zh/docs/kitex/Getting started/tutorial.md @@ -315,7 +315,7 @@ fi ``` output ├── bin // 存放二进制可执行文件 -│   └── example.shop.item +│   └── example.shop.item └── bootstrap.sh // 运行文件的脚本 ``` @@ -364,7 +364,7 @@ if err != nil { } ``` -上述代码中,`item.NewClient` 用于创建 `client`,其第一个参数为调用的 *服务名*,第二个参数为 *options*,用于传入可选参数, 此处的 `client.WithHostPorts` 用于指定服务端的地址,我们可以在运行商品服务时发现其监听在本地的 8888 端口,所以我们指定 8888 端口。更多参数可参考 [Client Option](https://www.cloudwego.cn/zh/docs/kitex/tutorials/options/client_options/) 一节。 +上述代码中,`item.NewClient` 用于创建 `client`,其第一个参数为调用的 _服务名_,第二个参数为 _options_,用于传入可选参数, 此处的 `client.WithHostPorts` 用于指定服务端的地址,我们可以在运行商品服务时发现其监听在本地的 8888 端口,所以我们指定 8888 端口。更多参数可参考 [Client Option](https://www.cloudwego.cn/zh/docs/kitex/tutorials/options/client_options/) 一节。 ### 调用服务 @@ -465,7 +465,7 @@ package main import ( "context" - + stock "example_shop/kitex_gen/example/shop/stock" ) @@ -480,7 +480,7 @@ func (s *StockServiceImpl) GetItemStock(ctx context.Context, req *stock.GetItemS } ``` - 由于之前的商品服务和 API 服务分别占用了 8888 和 8889 端口,故我们在库存服务的 `main.go` 中修改监听的端口: +由于之前的商品服务和 API 服务分别占用了 8888 和 8889 端口,故我们在库存服务的 `main.go` 中修改监听的端口: ```go package main @@ -587,7 +587,7 @@ func main() { if err != nil { log.Println(err.Error()) } -} +} ``` 由于库存服务跑在 8890 端口,所以我们指定 8890 端口创建客户端。 @@ -613,7 +613,7 @@ GetItemResp({Item:Item({Id:1024 Title:Kitex Description:Kitex is an excellent fr 为了更贴近真实环境,接下来为我们的服务接入注册中心,在本例中选择了 etcd 作为注册中心,etcd 的安装与使用可参考 [etcd.io](https://etcd.io/) 或使用下述 `docker compose` 文件,接下来默认你已经安装并启动 etcd 服务实例。 ```yml -version: '3' +version: "3" services: etcd: @@ -724,7 +724,7 @@ package main import ( "log" - + item "example_shop/kitex_gen/example/shop/item/itemservice" "github.com/cloudwego/kitex/pkg/rpcinfo" @@ -738,7 +738,7 @@ func main() { if err != nil { log.Fatal(err) } - + itemServiceImpl := new(ItemServiceImpl) stockCli, err := NewStockClient("0.0.0.0:8890") if err != nil { @@ -831,7 +831,7 @@ func NewStockClient() (stockservice.Client, error) { #### API 服务接入 -API 服务只有一个文件,我们在 `api/main.go` 的 `main` 函数中直接添加相关逻辑即可: +API 服务只有一个文件,我们在 `api/main.go` 的 `main` 函数中直接添加相关逻辑即可: ```go func main() { @@ -846,7 +846,7 @@ func main() { log.Fatal(err) } cli = c - + hz := server.New(server.WithHostPorts("localhost:8889")) hz.GET("/api/item", Handler) diff --git a/content/zh/docs/kitex/Overview/_index.md b/content/zh/docs/kitex/Overview/_index.md index b5acff6612..01bf0b6f57 100644 --- a/content/zh/docs/kitex/Overview/_index.md +++ b/content/zh/docs/kitex/Overview/_index.md @@ -11,7 +11,9 @@ description: "Kitex 架构设计、框架特点、框架性能。" Kitex[kaɪt'eks] 字节跳动内部的 Golang 微服务 RPC 框架,具有**高性能**、**强可扩展**的特点,在字节内部已广泛使用。如果对微服务性能有要求,又希望定制扩展融入自己的治理体系,Kitex 会是一个不错的选择。 ## 架构设计 + ![image](/img/docs/kitex.png) + ## 框架特点 - **高性能** @@ -37,7 +39,6 @@ Kitex[kaɪt'eks] 字节跳动内部的 Golang 微服务 RPC 框架,具有**高 - **服务治理** - 支持服务注册/发现、负载均衡、熔断、限流、重试、监控、链路跟踪、日志、诊断等服务治理模块,大部分均已提供默认扩展,使用者可选择集成。 - **代码生成** @@ -54,24 +55,23 @@ Kitex[kaɪt'eks] 字节跳动内部的 Golang 微服务 RPC 框架,具有**高 #### 测试环境 -* CPU: Intel(R) Xeon(R) Gold 5118 CPU @ 2.30GHz, 4 cores -* Memory: 8GB -* OS: Debian 5.4.56.bsk.1-amd64 x86_64 GNU/Linux -* Go: 1.15.4 +- CPU: Intel(R) Xeon(R) Gold 5118 CPU @ 2.30GHz, 4 cores +- Memory: 8GB +- OS: Debian 5.4.56.bsk.1-amd64 x86_64 GNU/Linux +- Go: 1.15.4 #### 并发表现 (Echo 1KB, 改变并发量) -| QPS | TP99 | TP999 | -| :--------------------------------------------------- | :---------------------------------------------------: | :----------------------------------------------------: | +| QPS | TP99 | TP999 | +| :------------------------------------------------- | :-------------------------------------------------: | :--------------------------------------------------: | | ![image](/img/docs/performance_concurrent_qps.png) | ![image](/img/docs/performance_concurrent_tp99.png) | ![image](/img/docs/performance_concurrent_tp999.png) | #### 吞吐表现 (并发 100, 改变包大小) -| QPS | TP99 | TP999 | -| :------------------------------------------------- | :-------------------------------------------------: | :--------------------------------------------------: | +| QPS | TP99 | TP999 | +| :----------------------------------------------- | :-----------------------------------------------: | :------------------------------------------------: | | ![image](/img/docs/performance_bodysize_qps.png) | ![image](/img/docs/performance_bodysize_tp99.png) | ![image](/img/docs/performance_bodysize_tp999.png) | - ### 相关项目 - [Netpoll](https://github.com/cloudwego/netpoll): 自研的高性能网络库,Kitex 默认集成的。 diff --git a/content/zh/docs/kitex/Reference/_index.md b/content/zh/docs/kitex/Reference/_index.md index fa5805a767..9e58534e7e 100644 --- a/content/zh/docs/kitex/Reference/_index.md +++ b/content/zh/docs/kitex/Reference/_index.md @@ -4,5 +4,4 @@ linkTitle: "参考" weight: 4 date: 2021-08-30 description: > - ---- \ No newline at end of file +--- diff --git a/content/zh/docs/kitex/Reference/exception.md b/content/zh/docs/kitex/Reference/exception.md index ba499ab222..8a8d403db4 100644 --- a/content/zh/docs/kitex/Reference/exception.md +++ b/content/zh/docs/kitex/Reference/exception.md @@ -79,7 +79,7 @@ Kitex 框架定义在 `github.com/cloudwego/kitex/pkg/kerrors` 下 `ErrRetry`, 重试时发生错误,具体错误见报错信息。 -### THRIFT 错误码 +### THRIFT 错误码 该类别对应 Thrift 框架原生的 Application Exception 错误,通常,这些错误会被 Kitex 框架包装成 `remote or network error` 。 @@ -151,5 +151,6 @@ if de.ErrorType() == kerrors.ErrInternalException {} // 返回 true ``` `DetailedError` 提供了下述方法用于获取更详细的信息: + 1. `ErrorType() error` ,用于获取基本错误类型 2. `Stack() string` ,用于获取堆栈信息(目前仅 `ErrPanic` 会带上) diff --git a/content/zh/docs/kitex/Reference/transport_protocol_ttheader.md b/content/zh/docs/kitex/Reference/transport_protocol_ttheader.md index 2d69fbd829..6f499f28de 100644 --- a/content/zh/docs/kitex/Reference/transport_protocol_ttheader.md +++ b/content/zh/docs/kitex/Reference/transport_protocol_ttheader.md @@ -51,8 +51,8 @@ description: "Kitex TTheader 协议设计。" 4. `SEQUENCE NUMBER` 字段 32bits,表示数据包的 seqId,可用于多路复用,最好确保单个连接内递增 5. `HEADER SIZE` 字段 16bits,等于头部长度字节数 /4,头部长度计算从第 14 个字节开始计算,一直到 `PAYLOAD` 前(备注:header 的最大长度为 64K) 6. `PROTOCOL ID` 字段 uint8 编码,取值有: - - ProtocolIDBinary = 0 - - ProtocolIDCompact = 2 + - ProtocolIDBinary = 0 + - ProtocolIDCompact = 2 7. `NUM TRANSFORMS` 字段 uint8 编码,表示 `TRANSFORM` 个数 8. `TRANSFORM ID` 字段 uint8 编码,具体取值参考下文 9. `INFO ID` 字段 uint8 编码,具体取值参考下文 @@ -66,7 +66,7 @@ Header 部分长度 bytes 数必须是 4 的倍数,不足部分用 `0x00` 填 表示压缩方式,为预留字段,暂不支持,取值有: -- ZLIB_TRANSFORM = 0x01,对应的 data 为空,表示用 `zlib` 压缩数据; +- ZLIB_TRANSFORM = 0x01,对应的 data 为空,表示用 `zlib` 压缩数据; - SNAPPY_TRANSFORM = 0x03,对应的 data 为空,表示用 `snappy` 压缩数据; ## Info IDs diff --git a/content/zh/docs/kitex/Tutorials/_index.md b/content/zh/docs/kitex/Tutorials/_index.md index d1126e719c..6307a19710 100755 --- a/content/zh/docs/kitex/Tutorials/_index.md +++ b/content/zh/docs/kitex/Tutorials/_index.md @@ -1,4 +1,3 @@ - --- title: "指南" linkTitle: "指南" @@ -6,6 +5,3 @@ weight: 3 date: 2022-12-23 description: Kitex 功能特性指南,包含基本特性、治理特性、高级特性、代码生成、框架扩展与 Option。 --- - - - diff --git a/content/zh/docs/kitex/Tutorials/advanced-feature/GLS.md b/content/zh/docs/kitex/Tutorials/advanced-feature/GLS.md index bad7006dcc..a97b139a53 100644 --- a/content/zh/docs/kitex/Tutorials/advanced-feature/GLS.md +++ b/content/zh/docs/kitex/Tutorials/advanced-feature/GLS.md @@ -2,7 +2,7 @@ title: "Goroutine-Local-Storage 功能使用" date: 2023-11-29 weight: 11 -keywords: ["GLS","上下文"] +keywords: ["GLS", "上下文"] description: "协程上下文隐式传递" --- @@ -11,7 +11,7 @@ description: "协程上下文隐式传递" GLS 用于存储 goroutine 内的上下文信息,作用类似于 context。相比 context 有如下优势: 1. **不需要显式传递**,在任意函数位置都可调用 CurSession() 获取上下文(如果有) -2. **可以在父子****协程****间传递**(需要开启选项) +2. **可以在父子\*\***协程\***\*间传递**(需要开启选项) 框架目前主要使用 GLS 进行 context 备份,以避免用户误传 context 导致链路透传信息(如 logid、metainfo 等)丢失 diff --git a/content/zh/docs/kitex/Tutorials/advanced-feature/_index.md b/content/zh/docs/kitex/Tutorials/advanced-feature/_index.md index 867b4ba943..0e5734867c 100644 --- a/content/zh/docs/kitex/Tutorials/advanced-feature/_index.md +++ b/content/zh/docs/kitex/Tutorials/advanced-feature/_index.md @@ -4,5 +4,4 @@ linkTitle: "高级特性" weight: 4 date: 2021-08-26 description: > - --- diff --git a/content/zh/docs/kitex/Tutorials/advanced-feature/codec_frugal.md b/content/zh/docs/kitex/Tutorials/advanced-feature/codec_frugal.md index 3f613953f4..e61dafc142 100644 --- a/content/zh/docs/kitex/Tutorials/advanced-feature/codec_frugal.md +++ b/content/zh/docs/kitex/Tutorials/advanced-feature/codec_frugal.md @@ -13,8 +13,9 @@ Github 项目主页: https://github.com/cloudwego/frugal ### Kitex 集成 说明: + 1. Server 端和 Client 端 **可以独立使用** frugal; - 1. 传输的数据都是按标准 thrift 协议进行编码的; + 1. 传输的数据都是按标准 thrift 协议进行编码的; 2. 如 Server 端开启 Frugal,需确保 Client 端指定了 Framed 或 TTHeaderFramed 协议; 3. 如使用 slim 模板,必须指定 PayloadCodec 为开启 frugal; @@ -27,6 +28,7 @@ Kitex 命令行工具内建了集成 frugal 的能力。 ###### **Frugal Tag: -thrift frugal_tag** 生成带有 frugal tag 的 Go struct,例如: + ```go type Request struct { Message string `thrift:"message,1" frugal:"1,default,string" json:"message"` @@ -34,11 +36,13 @@ type Request struct { ``` 说明: + 1. frugal 强依赖该 tag,例如 set 和 list 在 golang 对应的类型都是 slice,需通过 tag 区分; 2. 如无 frugal tag,kitex 会自动 fallback 到默认的 Go 编解码代码(前提是没使用 slim 模板); 3. 如果不希望生成 frugal tag,可使用 -thrift frugal_tag = false。 Kitex >= v0.5.0 **默认**指定了该参数;旧版本需重手动指定该参数、执行 kitex 命令,例: + ```bash kitex -thrift frugal_tag -service service_name idl/api.thrift ``` @@ -50,6 +54,7 @@ kitex -thrift frugal_tag -service service_name idl/api.thrift frugal 默认在首次编解码时调用 JIT Compiler,这会导致首次请求耗时较长。 例: + ```bash kitex -frugal-pretouch -service service_name idl/api.thrift ``` @@ -63,13 +68,13 @@ kitex -frugal-pretouch -service service_name idl/api.thrift frugal 用 JIT 生成编解码代码,不依赖生成的 Go 编解码代码。 例: + ```bash kitex -thrift frugal_tag,template=slim -service service_name idl/api.thrift ``` 注:开启 Slim 会导致在不支持 frugal 的情况下无法 fallback、只能报错(例如 arm 架构,或无法从请求头中获取 thrift payload 的长度)。 - ##### 示例用法 建议使用最新版 Kitex(>= v0.5.0)和 thriftgo(>= v0.3.0)。 @@ -81,6 +86,7 @@ kitex -thrift frugal_tag -service service_name idl/api.thrift ``` 说明: + 1. 新版 Kitex (>=0.5.0)默认会生成 frugal tag; 2. 不使用 pretouch:在单个项目里不一定所有类型都会被引用;可尝试打开后观察是否影响启动速度; 3. 不使用 slim 模板:在不支持 frugal 的场景可以 fallback 到生成的 Thrift 编解码代码; @@ -92,6 +98,7 @@ kitex -thrift frugal_tag,template=slim -frugal-pretouch -service service_name id ``` 说明: + 1. 开启 pretouch:可能会导致进程启动变慢 2. 启用 slim 模板:在不支持 frugal 的场景无法 fallback 到生成的 Thrift 编解码代码,只能报错; @@ -100,6 +107,7 @@ kitex -thrift frugal_tag,template=slim -frugal-pretouch -service service_name id ##### 注意事项 **请确保** Client 端指定了 Framed 模式(或 TTHeaderFramed) + - 使用 Framed 模式可以保证请求头包含 payload size - 如果无法获取到 Payload Size,目前 Kitex Server 只能 fallback 到 Go 编解码代码 - 如开启 slim 模板,则无法 fallback,会报错 “decode failed, codec msg type not match” @@ -117,6 +125,7 @@ server.WithPayloadCodec( thrift.NewThriftCodecWithConfig(thrift.FrugalRead | thrift.FrugalWrite) ) ``` + 注:如报错(找不到符号),说明当前 kitex 版本 + go 版本的组合不支持 frugal,例如 Go 1.21 + Kitex v0.7.1(Kitex 通过条件编译屏蔽不支持的版本)。 ##### 示例代码 @@ -172,14 +181,16 @@ client.WithPayloadCodec( ###### **client.WithTransportProtocol** 用于开启 Framed 模式,在 thrift pure payload 前增加 4 个字节(int32)用于告诉对端 payload size + ```go client.WithTransportProtocol(transport.Framed) ``` 注: + 1. 如不指定 Framed,可能存在如下问题: - 1. Server 端可能无法用 frugal 解码(因为读不到 Payload Size,详见 "Kitex Server -> 注意事项"); - 2. Server 端不会返回 Framed Payload,Client 可能无法用 frugal 解码(因为读不到 Payload Size); + 1. Server 端可能无法用 frugal 解码(因为读不到 Payload Size,详见 "Kitex Server -> 注意事项"); + 2. Server 端不会返回 Framed Payload,Client 可能无法用 frugal 解码(因为读不到 Payload Size); 2. 如果目标 Server 不支持 Framed,则不应指定。不影响 Client 侧使用 frugal 编码;但 Server 回包如不是 Framed,Client 可能无法用 frugal 解码(这种情况慎用 slim 模板); 3. 也可使用 TTHeaderFramed(即 `TTHeader | Framed` 位与结果)。 @@ -218,6 +229,7 @@ func main() { frugal 的 JIT 编译器依赖带 frugal tag 的 Go struct。 **注意:** + 1. 由于一个方法的请求可能有多个参数,需要构造一个将这些参数按顺序封装起来的 struct,例如 Kitex 生成的结构体 [EchoEchoArgs](https://github.com/cloudwego/kitex-examples/blob/v0.2.1/kitex_gen/api/echo.go#L469) 封装了 [Request](https://github.com/cloudwego/kitex-examples/blob/v0.2.1/kitex_gen/api/echo.go#L12); 2. 请求的响应虽然只有一个参数,但也要封装成一个 struct,例如 [EchoEchoResult](https://github.com/cloudwego/kitex-examples/blob/v0.2.1/kitex_gen/api/echo.go#L641) 封装了 [Response](https://github.com/cloudwego/kitex-examples/blob/v0.2.1/kitex_gen/api/echo.go#L176); 3. 具体可参考[示例代码](https://github.com/cloudwego/kitex-examples/blob/v0.2.2/frugal/codec/frugal.go)。 @@ -231,11 +243,13 @@ frugal 的 JIT 编译器依赖带 frugal tag 的 Go struct。 ##### 使用 thriftgo (>= v0.3.0) 安装 thriftgo ( >= v0.3.0): + ```bash go install -v github.com/cloudwego/thriftgo@latest ``` 基于 Thrift IDL 生成 Go struct: + ```go thriftgo -r -o thrift -g go:frugal_tag,template=slim,package_prefix=github.com/example echo.thrift ``` @@ -245,6 +259,7 @@ thriftgo -r -o thrift -g go:frugal_tag,template=slim,package_prefix=github.com/e 请参考 thriftgo 生成的 struct (例:[Request](https://github.com/cloudwego/kitex-examples/blob/v0.2.1/kitex_gen/api/echo.go#L12)、[Response](https://github.com/cloudwego/kitex-examples/blob/v0.2.1/kitex_gen/api/echo.go#L176))。 注意: + 1. 每个字段都应有 frugal tag; 2. 对于 optional 字段,需在 `InitDefault()` 方法里写入默认值; 3. 需要构造封装请求/响应参数的结构体(例:[EchoEchoArgs](https://github.com/cloudwego/kitex-examples/blob/v0.2.1/kitex_gen/api/echo.go#L469)、[EchoEchoResult](https://github.com/cloudwego/kitex-examples/blob/v0.2.1/kitex_gen/api/echo.go#L641)) @@ -254,6 +269,7 @@ thriftgo -r -o thrift -g go:frugal_tag,template=slim,package_prefix=github.com/e 如只想用 thrift 编码(例如替代 json),可直接调用 `frugal.EncodeObject(..)` 方法。 如想生成符合 [Thrift Binary protocol encoding](https://github.com/apache/thrift/blob/master/doc/specs/thrift-binary-protocol.md) 的 Thrift Payload(可发送给 Thrift Server),编码结果应含: + 1. Thrift Magic Number:int16,固定值 0x8001 2. MessageType:int16,枚举值 CALL=1, REPLY=2, Exception=3, Oneway=4 3. MethodName:长度(int32) + 名称([]byte) @@ -267,6 +283,7 @@ thriftgo -r -o thrift -g go:frugal_tag,template=slim,package_prefix=github.com/e #### 解码 根据 [Thrift Binary protocol encoding](https://github.com/apache/thrift/blob/master/doc/specs/thrift-binary-protocol.md),解码结果应包括: + 1. MethodName 2. MessageType 3. Sequence ID @@ -301,7 +318,6 @@ Kitex 解码时,需从 Header 中获取 Payload Size,以截取完整 Thrift - 在 Mac M1/M2 上开发时,可暂用 Rosetta 兼容 frugal - slim 模板不生成 Go 编解码代码(仅 JIT 编解码),因此**无法 fallback** 到默认的编解码方案 - ## 性能测试数据 传统的 Thrift 编解码方式,要求用户必须要先生成编解码代码,Frugal 通过 JIT 编译技术在运行时动态生成编解码机器代码,避免了这一过程。 @@ -353,9 +369,10 @@ UnmarshalAllSize_Parallel/large-16 4.80k ± 0% 0.76k ± 0% -84.10% 执行 kitex 命令行工具时加上参数 `-thrift frugal_tag=false`。 注意: + 1. 如果不生成 frugal_tag,会导致无法启用 frugal - 1. Thrift 的 set 和 list 在 golang 生成的类型一样,编码无法区分,所以需要 tag; - 2. kitex 检测到请求/响应类型不包含 tag,无法使用 frugal,则会 fallback 到标准的 thrift 编解码方式。 + 1. Thrift 的 set 和 list 在 golang 生成的类型一样,编码无法区分,所以需要 tag; + 2. kitex 检测到请求/响应类型不包含 tag,无法使用 frugal,则会 fallback 到标准的 thrift 编解码方式。 2. 如果开启 slim 模式,必须生成 frugal tag ### Kitex Client 报错 encode failed: codec msg type not match with thriftCodec @@ -365,6 +382,7 @@ Client 端报错信息如下: > failed with error: remote or network error[remote]: encode failed, codec msg type not match with thriftCodec 可能原因: + - 使用了 slim 模板,但**没有**指定 client.PayloadCodec 开启 frugal 编解码器 - 使用了 slim 模板,但**没有**生成带 frugal tag 的代码 @@ -375,6 +393,7 @@ Client 端报错信息如下: > decode failed, codec msg type not match with thriftCodec 可能原因: + - 使用了 slim 模板,但**没有**指定 server.PayloadCodec 开启 frugal 编解码器 - 使用了 slim 模板,但**没有**生成带 frugal tag 的代码 - Client 端**没有**指定 Transporting Protocol 为 Framed 或 TTHeaderFramed @@ -396,9 +415,10 @@ frugal <= v0.1.3 解码 string 类型时,默认使用 NOCOPY 模式(直接 ### 编译 Kitex 项目时报错 undefined: thrift.FrugalRead 可能原因: + 1. 使用了不支持的版本 go 编译:使用 go1.16 ~ go1.21 进行编译 2. 使用了不支持当前 Go 版本的 Kitex 版本:请升级到最新版 Kitex - 1. 例如:Kitex v0.7.1 在用 go1.21 编译时禁用了 frugal(发布该 Kitex 版本时 frugal 尚未支持 go1.21),需要升级到 Kitex >= v0.7.2 + 1. 例如:Kitex v0.7.1 在用 go1.21 编译时禁用了 frugal(发布该 Kitex 版本时 frugal 尚未支持 go1.21),需要升级到 Kitex >= v0.7.2 ### slim 模板下,Optional 字段解码时未填充默认值 @@ -417,10 +437,11 @@ frugal <= v0.1.3 解码 string 类型时,默认使用 NOCOPY 模式(直接 ### frugal EncodeObject panic 可能是旧版本的问题,建议升级到最新版( >= v0.1.8) + ```bash go get github.com/cloudwego/frugal@latest ``` 如果问题依然存在,请确认被 encode 的对象没有被并发读写(包括间接引用的其他对象)。 -例如读取一个正被设置为空串的字符串,可能会读到无效的 string(StringHeader.Data = nil && StringHeader.Len > 0),导致在编码时 出现 "nil pointer error" panic 。 \ No newline at end of file +例如读取一个正被设置为空串的字符串,可能会读到无效的 string(StringHeader.Data = nil && StringHeader.Len > 0),导致在编码时 出现 "nil pointer error" panic 。 diff --git a/content/zh/docs/kitex/Tutorials/advanced-feature/error_handler.md b/content/zh/docs/kitex/Tutorials/advanced-feature/error_handler.md index bbed470a4a..1258f75693 100644 --- a/content/zh/docs/kitex/Tutorials/advanced-feature/error_handler.md +++ b/content/zh/docs/kitex/Tutorials/advanced-feature/error_handler.md @@ -10,7 +10,7 @@ description: RPC 基于协议进行通信,且 RPC 并没有统一的错误码 ## 建议使用方式 -ErrorHandler 通过 client/server 的 Option 配置,但通常一个微服务体系会有统一的异常处理规范,如果是企业用户建议通过 [Suite](../../framework-exten/suite) 封装定制 Option,服务开发者就不用具体关注异常处理的配置。 +ErrorHandler 通过 client/server 的 Option 配置,但通常一个微服务体系会有统一的异常处理规范,如果是企业用户建议通过 [Suite](../../framework-exten/suite) 封装定制 Option,服务开发者就不用具体关注异常处理的配置。 ### 服务端配置 @@ -21,7 +21,7 @@ server.WithErrorHandler(yourServerErrorHandler) 该函数会在服务端 handler 执行后,中间件执行前被执行,可以用于给调用端返回自定义的错误码和信息。注意,虽然对此提供了支持,但业务层面自定义的错误码依然不建议通过 ErrorHandler 处理,因为我们希望将 RPC 错误和业务的错误能够区分开,RPC 错误表示一次RPC 请求失败,比如超时、熔断、限流,从 RPC 层面是失败的请求,但业务错误属于业务逻辑层面,在 RPC 层面其实是请求成功。Kitex 会制定一个业务[自定义异常规范](https://github.com/cloudwego/kitex/issues/511)用于区分业务错误和 RPC 层面错误。 -* ErrorHandler 示例: +- ErrorHandler 示例: Kitex 对 server handler 返回的 error 统一封装为 kerrors.ErrBiz,如果要获取原始的 error 需要先进行 Unwrap。 @@ -30,7 +30,7 @@ server.WithErrorHandler(yourServerErrorHandler) func ServerErrorHandler(ctx context.Context, err error) error { // if you want get other rpc info, you can get rpcinfo first, like `ri := rpcinfo.GetRPCInfo(ctx)` // for example, get remote address: `remoteAddr := rpcinfo.GetRPCInfo(ctx).From().Address()` - + if errors.Is(err, kerrors.ErrBiz) { err = errors.Unwrap(err) } @@ -62,15 +62,15 @@ func ServerErrorHandler(ctx context.Context, err error) error { client.WithErrorHandler(yourClientErrorHandler) ``` -该 handler 在远程调用结束,中间件执行前被执行。框架有默认的 ClientErrorHandler,如果未配置将使用默认的,默认 Handler 的行为是:接收到服务端的错误返回或者调用端在传输层出现了异常,统一返回 **ErrRemoteOrNetwork**。另外,对于 Thrift 和 KitexProtobuf,error msg 会包含 '[remote]' 信息用来标识这是对端的错误;对于 gRPC 如果对端通过 `status.Error` 构造的错误返回,本端使用 `status.FromError(err)` 可以获取 `*status.Status`,注意 `Status` 需使用 Kitex 提供的,包路径是 `github.com/cloudwego/kitex/pkg/remote/trans/nphttp2/status`。 +该 handler 在远程调用结束,中间件执行前被执行。框架有默认的 ClientErrorHandler,如果未配置将使用默认的,默认 Handler 的行为是:接收到服务端的错误返回或者调用端在传输层出现了异常,统一返回 **ErrRemoteOrNetwork**。另外,对于 Thrift 和 KitexProtobuf,error msg 会包含 '[remote]' 信息用来标识这是对端的错误;对于 gRPC 如果对端通过 `status.Error` 构造的错误返回,本端使用 `status.FromError(err)` 可以获取 `*status.Status`,注意 `Status` 需使用 Kitex 提供的,包路径是 `github.com/cloudwego/kitex/pkg/remote/trans/nphttp2/status`。 -* ErrorHandler 示例: +- ErrorHandler 示例: ```go func ClientErrorHandler(ctx context.Context, err error) error { // if you want get other rpc info, you can get rpcinfo first, like `ri := rpcinfo.GetRPCInfo(ctx)` // for example, get remote address: `remoteAddr := rpcinfo.GetRPCInfo(ctx).To().Address()` - + // for thrift、KitexProtobuf if e, ok := err.(*remote.TransError); ok { // TypeID is error code @@ -84,20 +84,16 @@ func ClientErrorHandler(ctx context.Context, err error) error { } ``` - ### 错误码定义范围 因为部分错误码是框架内置的,所以使用者应当避开内置错误码,目前内置的错误码: -* Thrift、KitexProtobuf:0 - 10。 - -* gRPC:0 - 17。 +- Thrift、KitexProtobuf:0 - 10。 +- gRPC:0 - 17。 ## ErrorHandler 执行机制 ErrorHandler 在 Middleware 中被执行,无论是调用端还是服务端 ErrorHandler 都作为最里层的 Middleware 被执行,如图所示: ![middleware_errorhandler](/img/docs/middleware_errorhandler.png) - - diff --git a/content/zh/docs/kitex/Tutorials/advanced-feature/generic-call/_index.md b/content/zh/docs/kitex/Tutorials/advanced-feature/generic-call/_index.md index 3cad60bb1f..47edc7b275 100644 --- a/content/zh/docs/kitex/Tutorials/advanced-feature/generic-call/_index.md +++ b/content/zh/docs/kitex/Tutorials/advanced-feature/generic-call/_index.md @@ -7,4 +7,3 @@ description: Kitex 支持 Thrift 与 Protobuf 泛化调用,无需将维护编 --- 在传统的 RPC 调用中,客户端通常需要依赖于服务端 IDL,即其定义的服务接口、参数结构、数据类型等信息,基于 IDL 生成代码后发起 RPC 调用。但是,对于 API 网关、接口测试平台这类通用型的平台服务,有成千上万的服务接入,让平台依赖所有服务的 IDL 生成代码去发起 RPC 调用是不现实的。在此背景下,RPC 泛化调用出现了,即提供一种泛化接口,接受如 JSON、Map 此类数据,转化为 RPC 协议规定的数据格式后发起调用。 - diff --git a/content/zh/docs/kitex/Tutorials/advanced-feature/generic-call/basic_usage.md b/content/zh/docs/kitex/Tutorials/advanced-feature/generic-call/basic_usage.md index d9fc6ea752..df13ee599f 100644 --- a/content/zh/docs/kitex/Tutorials/advanced-feature/generic-call/basic_usage.md +++ b/content/zh/docs/kitex/Tutorials/advanced-feature/generic-call/basic_usage.md @@ -4,7 +4,6 @@ date: 2024-01-24 weight: 2 keywords: ["generic-call", "HTTP", "Thrift"] description: "泛化调用基本使用" - --- ## IDL Provider @@ -44,7 +43,7 @@ if err != nil { } ``` -`generic.NewThriftFileProviderWithDynamicGo` 在处理 RPC 数据时接入了 [dynamicgo](https://github.com/cloudwego/dynamicgo) 用于提高性能。详情见[接入 dynamicgo 指南](/zh/docs/kitex/tutorials/advanced-feature/generic-call/generic-call-dynamicgo/)。 +`generic.NewThriftFileProviderWithDynamicGo` 在处理 RPC 数据时接入了 [dynamicgo](https://github.com/cloudwego/dynamicgo) 用于提高性能。详情见[接入 dynamicgo 指南](/zh/docs/kitex/tutorials/advanced-feature/generic-call/generic-call-dynamicgo/)。 #### Protobuf @@ -94,7 +93,7 @@ if err != nil { } ``` -`generic.NewThriftContentProviderWithDynamicGo` 在处理 RPC 数据时接入了 [dynamicgo](https://github.com/cloudwego/dynamicgo) 用于提高性能。详情见[接入 dynamicgo 指南](/zh/docs/kitex/tutorials/advanced-feature/generic-call/generic-call-dynamicgo/)。 +`generic.NewThriftContentProviderWithDynamicGo` 在处理 RPC 数据时接入了 [dynamicgo](https://github.com/cloudwego/dynamicgo) 用于提高性能。详情见[接入 dynamicgo 指南](/zh/docs/kitex/tutorials/advanced-feature/generic-call/generic-call-dynamicgo/)。 #### Protobuf @@ -129,7 +128,7 @@ if err != nil { 目前仅 Thrift 支持此功能。 -若为方便构造 IDL Map,也可以通过 `generic.NewThriftContentWithAbsIncludePathProvider` 或 `generic.NewThriftContentWithAbsIncludePathProviderWithDynamicGo` 使用绝对路径作为 Key。 +若为方便构造 IDL Map,也可以通过 `generic.NewThriftContentWithAbsIncludePathProvider` 或 `generic.NewThriftContentWithAbsIncludePathProviderWithDynamicGo` 使用绝对路径作为 Key。 ```go content := ` @@ -221,6 +220,7 @@ type Service interface { Kitex 支持以下场景的泛化调用: 1. Thrift: + - 二进制泛化调用 - HTTP 映射泛化调用 - Map 映射泛化调用 @@ -731,7 +731,7 @@ func main() { // resp 类型为 map[string]interface{} resp, err := cli.GenericCall(ctx, "ExampleMethod", map[string]interface{}{ "Msg": "hello", - }) + }) } ``` @@ -1138,8 +1138,3 @@ func main() { } } ``` - - - - - diff --git a/content/zh/docs/kitex/Tutorials/advanced-feature/generic-call/generic-call-dynamicgo.md b/content/zh/docs/kitex/Tutorials/advanced-feature/generic-call/generic-call-dynamicgo.md index c14aebac34..89f84afa06 100644 --- a/content/zh/docs/kitex/Tutorials/advanced-feature/generic-call/generic-call-dynamicgo.md +++ b/content/zh/docs/kitex/Tutorials/advanced-feature/generic-call/generic-call-dynamicgo.md @@ -2,7 +2,7 @@ title: "泛化调用接入 dynamicgo 指南" date: 2023-12-17 weight: 4 -keywords: ["generic-call","dynamicgo"] +keywords: ["generic-call", "dynamicgo"] description: "泛化调用接入 dynamicgo 指南;高性能泛化调用实现" --- @@ -28,6 +28,7 @@ description: "泛化调用接入 dynamicgo 指南;高性能泛化调用实现" - 您可以 IDL 与旧方法相同的方法 `UpdateIDL` - `NewThriftContentWithAbsIncludePathProviderWithDynamicGo(mainIDLPath字符串,包括map[string]string)`:创建 ThriftContentWithAbsIncludePathProvider 实现 DescriptorProvider(absinclude path)和从 content - 您可以与旧方法相同的方法更新 IDL + - Provider option - `GetProviderOption` 是一个接口,其中包含一个 func `Option()` 来获取 `ProviderOption`。ProviderOption 有一个 bool 字段 `DynamicGoEnable`,它指示是否启用了 Dynamicgo。 @@ -73,6 +74,7 @@ DefaultHTTPDynamicgoConvOpts = conv.Options{ - 使用 Dynamicgo:`remote or network error[remote]: {"code":400,"msg":"this is an exception"}` - HTTP generic call (TODO) HTTP 的泛化调用不支持 thrift 异常字段处理。 + - 类型转换 - Bool <> string:在 Kitex 的原始方式中,即使 IDL 声明为 bool 类型的字段值为字符串(例如"true"),它也可以被编码,但是 Dynamicgo 在编码过程中会产生错误。 @@ -86,6 +88,7 @@ DefaultHTTPDynamicgoConvOpts = conv.Options{ - `ProviderOption.DynamicGoEnable` 值为 true - 在服务器端:客户端使用 json 泛化调用,或者客户端不使用 json 泛化调用但传输协议**不是** PurePayload。 + - HTTP 泛化 - `ProviderOption.DynamicGoEnable` 值为 true @@ -93,10 +96,10 @@ DefaultHTTPDynamicgoConvOpts = conv.Options{ **如果不满足这些条件,将 fallback 到原来的泛化调用实现。** -| **开启条件** | 宿主机环境 | 选项 | -| ------------ | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| **开启条件** | 宿主机环境 | 选项 | +| ------------ | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | **json** | CPU 架构:amd64 && go>=1.16 | - `ProviderOption` 的 `DynamicGoEnable` 为 true
- 客户端使用 泛化调用,或者其传输协议使用的是 TTHeader、Framed、TTHeaderFramed 中的一种 | -| http | CPU 架构:amd64 && go>=1.16 | - `ProviderOption` 的 `DynamicGoEnable` 为 true
- `UseRawBodyForHTTPResp(true)` **启用(可选)** | +| http | CPU 架构:amd64 && go>=1.16 | - `ProviderOption` 的 `DynamicGoEnable` 为 true
- `UseRawBodyForHTTPResp(true)` **启用(可选)** | ## JSON 泛化调用示例 @@ -200,7 +203,7 @@ type GenericServiceImpl struct { } func (g *GenericServiceImpl) GenericCall(ctx context.Context, method string, request interface{}) (response interface{}, err error) { - // use jsoniter or other json parse sdk to assert request + // use jsoniter or other json parse sdk to assert request m := request.(string) fmt.Printf("Recv: %v\n", m) return "{\"Msg\": \"world\"}", nil @@ -217,11 +220,11 @@ func (g *GenericServiceImpl) GenericCall(ctx context.Context, method string, req - 请求 -类型:*generic.HTTPRequest +类型:\*generic.HTTPRequest - 回应 -类型:*generic.HTTPResponse +类型:\*generic.HTTPResponse ```go package main @@ -251,7 +254,7 @@ func main() { if err != nil { panic(err) } - + // Construct the request, or get it from ginex body := map[string]interface{}{ "text": "text", @@ -279,11 +282,11 @@ func main() { customReq, err := generic.FromHTTPRequest(req) // Considering that the business may use third-party http request, you can construct your own conversion function // customReq *generic.HttpRequest // Since the method for http generic is obtained from the http request via the bam rule, just fill in the blanks - + resp, err := cli.GenericCall(ctx, "", customReq) realResp := resp.(*generic.HttpResponse) realResp.Write(w) // Write back to ResponseWriter for http gateway - + // The body will be stored in RawBody of HTTPResponse as []byte type. // Without using dynamicgo, the body will be stored in Body of HTTPResponse as map[string]interface{} type. node, err := sonic.Get(gr.RawBody, "msg") @@ -322,5 +325,3 @@ func main() { | | 10K | original | 8002.70 | 97.59ms | 149.83ms | 149.53 | 1524.45 | 0% | | | | dynamicgo | 26857.57 | 9.47ms | 21.94ms | 394.42 | 1138.70 | +236% | | | | fallback | 8019.39 | 97.11ms | 149.50ms | 148.03 | 1527.77 | +0.2% | - - diff --git a/content/zh/docs/kitex/Tutorials/advanced-feature/generic-call/thrift_idl_annotation_standards.md b/content/zh/docs/kitex/Tutorials/advanced-feature/generic-call/thrift_idl_annotation_standards.md index a15a14fc58..3e34bb1d59 100644 --- a/content/zh/docs/kitex/Tutorials/advanced-feature/generic-call/thrift_idl_annotation_standards.md +++ b/content/zh/docs/kitex/Tutorials/advanced-feature/generic-call/thrift_idl_annotation_standards.md @@ -6,10 +6,9 @@ weight: 3 description: > --- - -| 日期 | 版本 | 作者 | 变更内容 | -| ---------- | ----- | ----- | ------------------------------- | -| 2022-05-22 | v1.0 | 王景佩 | 第一版 Thrift-HTTP 映射的 IDL 规范 | +| 日期 | 版本 | 作者 | 变更内容 | +| ---------- | ---- | ------ | ---------------------------------- | +| 2022-05-22 | v1.0 | 王景佩 | 第一版 Thrift-HTTP 映射的 IDL 规范 | 本规范是 `Thrift` 与 `HTTP` 接口映射的 IDL 定义标准,包括服务、接口以及请求 `request`、`response` 参数定义规范和错误码定义规范。Kitex 部分实现了该规范,注解说明有标注支持情况。 @@ -26,8 +25,8 @@ description: > - 一个服务 service 对应一个 thrift 主文件,主文件里的 `method` 都是针对当前服务对应接口,主文件可以引用其它 thrift 文件定义 - 每个 `Method` 原则上对应一个 `Request` 和 `Response` 定义 - 原则上不建议 `Request` 复用,可以复用 `Response` - -## Request 规范 + +## Request 规范 ### 约束 @@ -37,17 +36,17 @@ description: > ### 注解说明 -| 注解 | 说明 | 字段约束 | Kitex 支持情况 | -| --- | ---- | ------ | ------------ | -| `api.query` | `api.query` 对应 HTTP 请求的 url query 参数 | 只支持基本类型(`object`, `map` 以外)和逗号分隔的 `list` | 支持 | -| `api.path` | `api.path` 对应 HTTP 请求的 url path 参数 | 支持基本类型 | 支持 | -| `api.header` | `api.header` 对应 HTTP 请求的 header 参数 | 只支持基本类型和逗号分隔的`list` | 支持 | -| `api.cookie` | `api.cookie` 对应 HTTP 的 cookie 参数 | 支持基本类型 | 支持 | -| `api.body` | `api.body` 对应 HTTP 的 body 参数
支持 body 为 `json` 和 `form` 两种格式 |在未指定接口序列化方式下默认`json`格式,也可以在`method`注解中使用`api.serializer`来指定`json/form` | 支持,但目前仅支持 `JSON` 格式 | -| `api.raw_body` | `api.raw_body` HTTP 原始 body,少数接口 body 加密了,可以拿到原始的 body(二进制数组) | | 支持 | -| `api.vd` | 参数校验,使用了[HTTPs://github.com/bytedance/go-tagexpr/tree/master/validator](HTTPs://github.com/bytedance/go-tagexpr/tree/master/validator)库,检验表达式语法参见包内readme文件 | | 暂未支持 | -| `api.js_conv` | `api.js_conv` 标识该字段传入参数需要进行 string to int64 转换,来解决前端 js 不支持 int64 的场景 |value通常写true,其它情况与不写该注解等价 | 支持 | -| `api.raw_uri` | `api.raw_uri` 用于 HTTP to RPC 协议转换,RPC 服务获取 HTTP接口对应的原始 uri | 只支持 `string` 类型 | 暂未支持 | +| 注解 | 说明 | 字段约束 | Kitex 支持情况 | +| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ------------------------------ | +| `api.query` | `api.query` 对应 HTTP 请求的 url query 参数 | 只支持基本类型(`object`, `map` 以外)和逗号分隔的 `list` | 支持 | +| `api.path` | `api.path` 对应 HTTP 请求的 url path 参数 | 支持基本类型 | 支持 | +| `api.header` | `api.header` 对应 HTTP 请求的 header 参数 | 只支持基本类型和逗号分隔的`list` | 支持 | +| `api.cookie` | `api.cookie` 对应 HTTP 的 cookie 参数 | 支持基本类型 | 支持 | +| `api.body` | `api.body` 对应 HTTP 的 body 参数
支持 body 为 `json` 和 `form` 两种格式 | 在未指定接口序列化方式下默认`json`格式,也可以在`method`注解中使用`api.serializer`来指定`json/form` | 支持,但目前仅支持 `JSON` 格式 | +| `api.raw_body` | `api.raw_body` HTTP 原始 body,少数接口 body 加密了,可以拿到原始的 body(二进制数组) | | 支持 | +| `api.vd` | 参数校验,使用了[HTTPs://github.com/bytedance/go-tagexpr/tree/master/validator](HTTPs://github.com/bytedance/go-tagexpr/tree/master/validator)库,检验表达式语法参见包内readme文件 | | 暂未支持 | +| `api.js_conv` | `api.js_conv` 标识该字段传入参数需要进行 string to int64 转换,来解决前端 js 不支持 int64 的场景 | value通常写true,其它情况与不写该注解等价 | 支持 | +| `api.raw_uri` | `api.raw_uri` 用于 HTTP to RPC 协议转换,RPC 服务获取 HTTP接口对应的原始 uri | 只支持 `string` 类型 | 暂未支持 | ### 举例 @@ -73,24 +72,24 @@ struct BizRequest { } ``` -## Response 规范 +## Response 规范 ### 约束 - `header` 不支持除逗号相隔并且 `value` 为基本类型的 `list` 以外的复杂类型 - 直接按照业务自己定义的 `response。默认` `json` 序列化到 `body`,`key`为字段名,注解可为空 -### 注解说明 +### 注解说明 -| 注解 | 说明 | 字段约束 | Kitex 支持情况 | -| --- | ---- | ------ | ------------- | -| `api.header` |`api.header` 设置HTTP 请求回复中的header | 只支持基本类型和逗号分隔的`list` | 支持 | -| `api.http_code` | `api.http_code` 对应HTTP 回复中的status code,200/500等 |value通常写`true`,其它情况与不写该注解等价 | 支持 | -| `api.body` | `api.body` 对应HTTP 回复中的body参数 | | 支持 | -| `api.none` | 标识该字段在 `response`中将会被忽略|value通常写`true`,其它情况与不写该注解等价| 支持 | -| `api.js_conv` | 兼容js int64问题,`response`时需要将int64表示为string|value通常写`true`,其它情况与不写该注解等价| 支持 | -| `api.raw_body` | `api.raw_body` 设置该字段`content`作为HTTP response的完整body | | 支持 | -| `api.cookie` | `api.cookie` 设置HTTP 回复中的cookie (`string`类型,后端自行拼接) | | 支持 | +| 注解 | 说明 | 字段约束 | Kitex 支持情况 | +| --------------- | ------------------------------------------------------------------- | ------------------------------------------- | -------------- | +| `api.header` | `api.header` 设置HTTP 请求回复中的header | 只支持基本类型和逗号分隔的`list` | 支持 | +| `api.http_code` | `api.http_code` 对应HTTP 回复中的status code,200/500等 | value通常写`true`,其它情况与不写该注解等价 | 支持 | +| `api.body` | `api.body` 对应HTTP 回复中的body参数 | | 支持 | +| `api.none` | 标识该字段在 `response`中将会被忽略 | value通常写`true`,其它情况与不写该注解等价 | 支持 | +| `api.js_conv` | 兼容js int64问题,`response`时需要将int64表示为string | value通常写`true`,其它情况与不写该注解等价 | 支持 | +| `api.raw_body` | `api.raw_body` 设置该字段`content`作为HTTP response的完整body | | 支持 | +| `api.cookie` | `api.cookie` 设置HTTP 回复中的cookie (`string`类型,后端自行拼接) | | 支持 | ### 举例 @@ -101,36 +100,36 @@ struct RspItem{ 2: optional string text } struct BizResponse { - 1: optional string T (api.header= 'T') + 1: optional string T (api.header= 'T') // 该字段将填入给客户端返回的header中 2: optional map rsp_items (api.body='rsp_items') // 一级key = 'rsp_items' 3: optional i32 v_enum (api.none = 'true') // 该注解value通常写true,其它情况与不写该注解等价 4: optional list rsp_item_list (api.body = 'rsp_item_list') - // 业务自己指定了HTTPCode, 如果没有指定, baseResp.StatusCode=0 -> HTTPCode=200, 其他 HTTPCode=500 + // 业务自己指定了HTTPCode, 如果没有指定, baseResp.StatusCode=0 -> HTTPCode=200, 其他 HTTPCode=500 5: optional i32 http_code (api.http_code = 'true') //对应 response HTTP Code 6: optional list item_count (api.header = 'item_count') // 当设置header时以逗号相隔的列表 7: optional string token (api.cookie = 'token') // 对应 response Cookie 字段 } ``` -## Method 规范 +## Method 规范 ### 约束 - 如果是`GET`请求,`api.serializer`定义的序列化方式是无效的 - 每个URI对应IDL的一个`method`,通过注解关联,注解不可为空 -### 注解说明 +### 注解说明 -| 注解 | 类型 | 说明 | 举例 | Kitex 支持情况 | -| --- | ---- | --- | --- | ------------- | -| `api.get` | `string` | `get`请求,值为HTTP path,uri的语法与gin一致(参考 [httprouter](https://github.com/julienschmidt/httprouter)) | 例如 `api.get = '/life/client/favorite/collect'` | 支持 | -| `api.post` | `string` | `post`请求,值为HTTP path,uri的语法与gin一致(参考 [httprouter](https://github.com/julienschmidt/httprouter)) | 例如 `api.post='/life/client/favorite/collect'` | 支持 | -| `api.put` | `string` | `put`请求,值为HTTP path,uri的语法与gin一致(参考 [httprouter](https://github.com/julienschmidt/httprouter)) | 例如
`api.put='/life/client/favorite/collect'` | 支持 | -| `api.delete` | `string` | `delete`请求,值为HTTP path,uri的语法与gin一致(参考 [httprouter](https://github.com/julienschmidt/httprouter)) | `api.delete='/life/client/favorite/collect'` | 支持 | -| `api.patch` | `string` | `delete`请求,值为HTTP path,uri的语法与gin一致(参考 [httprouter](https://github.com/julienschmidt/httprouter)) | `api.patch='/life/client/favorite/collect'` | 支持 | -| `api.serializer` | `string` | 客户端请求体序列化方式 | 如`form`, `json`, `thrift`, `pb`等 | 暂未支持 | +| 注解 | 类型 | 说明 | 举例 | Kitex 支持情况 | +| ---------------- | -------- | --------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | -------------- | +| `api.get` | `string` | `get`请求,值为HTTP path,uri的语法与gin一致(参考 [httprouter](https://github.com/julienschmidt/httprouter)) | 例如 `api.get = '/life/client/favorite/collect'` | 支持 | +| `api.post` | `string` | `post`请求,值为HTTP path,uri的语法与gin一致(参考 [httprouter](https://github.com/julienschmidt/httprouter)) | 例如 `api.post='/life/client/favorite/collect'` | 支持 | +| `api.put` | `string` | `put`请求,值为HTTP path,uri的语法与gin一致(参考 [httprouter](https://github.com/julienschmidt/httprouter)) | 例如
`api.put='/life/client/favorite/collect'` | 支持 | +| `api.delete` | `string` | `delete`请求,值为HTTP path,uri的语法与gin一致(参考 [httprouter](https://github.com/julienschmidt/httprouter)) | `api.delete='/life/client/favorite/collect'` | 支持 | +| `api.patch` | `string` | `delete`请求,值为HTTP path,uri的语法与gin一致(参考 [httprouter](https://github.com/julienschmidt/httprouter)) | `api.patch='/life/client/favorite/collect'` | 支持 | +| `api.serializer` | `string` | 客户端请求体序列化方式 | 如`form`, `json`, `thrift`, `pb`等 | 暂未支持 | ### 举例 @@ -138,25 +137,25 @@ struct BizResponse { service BizService{ // 例子1: get请求 BizResponse BizMethod1(1: biz.BizRequest req)( - api.get = '/life/client/:action/:biz', - api.baseurl = 'ib.snssdk.com', + api.get = '/life/client/:action/:biz', + api.baseurl = 'ib.snssdk.com', api.param = 'true', api.category = 'demo' ) // 例子2: post请求 BizResponse BizMethod2(1: biz.BizRequest req)( - api.post = '/life/client/:action/:biz', - api.baseurl = 'ib.snssdk.com', - api.param = 'true', + api.post = '/life/client/:action/:biz', + api.baseurl = 'ib.snssdk.com', + api.param = 'true', api.serializer = 'form' ) // 例子3: delete请求 BizResponse BizMethod3(1: biz.BizRequest req)( - api.post = '/life/client/:action/:biz', - api.baseurl = 'ib.snssdk.com', - api.param = 'true', + api.post = '/life/client/:action/:biz', + api.baseurl = 'ib.snssdk.com', + api.param = 'true', api.serializer = 'json' ) } diff --git a/content/zh/docs/kitex/Tutorials/advanced-feature/metainfo.md b/content/zh/docs/kitex/Tutorials/advanced-feature/metainfo.md index 5caea95f6b..a5204ac343 100644 --- a/content/zh/docs/kitex/Tutorials/advanced-feature/metainfo.md +++ b/content/zh/docs/kitex/Tutorials/advanced-feature/metainfo.md @@ -12,11 +12,10 @@ description: 除了 IDl 定义的数据结构外,Kitex 支持额外的元信 然而在实际生产环境,我们偶尔会有特殊的信息需要传递给对端服务,而又不希望将这些可能是临时或者格式不确定的内容显式定义在 IDL 里面,这就需要框架能够支持一定的元信息传递能力。 -**注意** *必须使用支持元信息的透传的底层传输协议才可用,例如 TTheader、HTTP、gRPC*。 +**注意** _必须使用支持元信息的透传的底层传输协议才可用,例如 TTheader、HTTP、gRPC_。 为了和底层的协议解耦,同时也为了支持与不同框架之间的互通,Kitex 并没有直接提供读写底层传输协议的元信息的 API,而是通过一个独立维护的基础库 [metainfo][metainfo] 来支持元信息的传递。 - ## 正向元信息传递 包 [metainfo][metainfo] 提供了两种类型的正向元信息传递 API:临时的(transient)和持续的(persistent)。前者适用于通常的元信息传递的需求;后者是在对元信息有持续传递需求的场合下使用,例如日志 ID、染色等场合,当然,持续传递的前提是下游以及更下游的服务都是支持这一套数据透传的约定,例如都是 Kitex 服务。 @@ -112,19 +111,20 @@ func (MyServiceImpl) SomeMethod(ctx context.Context, req *SomeRequest) (res *Som } ``` - [metainfo]: https://pkg.go.dev/github.com/bytedance/gopkg/cloud/metainfo ## Kitex gRPC metadata -Kitex gRPC 场景也可以同样使用 metainfo。但注意,需要满足用大写 + '_' 格式的 CGI 网关风格接口的 key 。 +Kitex gRPC 场景也可以同样使用 metainfo。但注意,需要满足用大写 + '\_' 格式的 CGI 网关风格接口的 key 。 除了 metainfo 用法,也兼容了原本的 metadata 传输方式。但二者不可混合使用。 与原生 gRPC 类似,正向传递通过 metadata 实现。反向传递通过 Header 或者 Trailer 发回,具体用法如下: ### 正向传递 + Client 发送设置: + ```golang ctx := metadata.AppendToOutgoingContext(ctx, "k1", "v1", "k1", "v2", "k2", "v3") // unary 场景 @@ -132,7 +132,9 @@ Client 发送设置: // stream 场景 stream, err := client.CallStream(ctx) ``` + Server 接收: + ```golang // unary 场景 md, ok := metadata.FromIncomingContext(ctx) @@ -140,19 +142,22 @@ Server 接收: md, ok := metadata.FromIncomingContext(stream.Context()) ``` - - ### 反向传递 + #### Unary + Unary 场景中,Server 向 Client 发送元信息方式如下: Server 设置: + ```golang nphttp2.SendHeader(ctx, metadata.Pairs("k1", "v1")) nphttp2.SetHeader(ctx, metadata.Pairs("k1", "v1")) nphttp2.SetTrailer(ctx, metadata.Pairs("k2", "v2")) ``` + Client 接收: + ```golang // 提前设置 var header, trailer metadata.MD @@ -164,17 +169,21 @@ Client 接收: log.Println("header is ", header) log.Println("trailer is ", trailer) ``` + #### Streaming + Streaming 场景中,Server 向 Client 发送元信息方式如下: Server 发送: + ```golang stream.SetHeader(metadata.Pairs("k1", "v1")) stream.SetTrailer(metadata.Pairs("k2","v2")) ``` + Client 接收: + ```golang // 发起 stream call 之后 md, _ := stream.Header() md = stream.Trailer() ``` - diff --git a/content/zh/docs/kitex/Tutorials/advanced-feature/multi_service.md b/content/zh/docs/kitex/Tutorials/advanced-feature/multi_service.md index c116a335b8..d1eb0c2585 100644 --- a/content/zh/docs/kitex/Tutorials/advanced-feature/multi_service.md +++ b/content/zh/docs/kitex/Tutorials/advanced-feature/multi_service.md @@ -2,7 +2,8 @@ title: "单 Server 多 Service" date: 2023-03-05 weight: 10 -keywords: ["Kitex", "多 Service", "单 Server 多 Service", "gRPC", "thrift", "protobuf"] +keywords: + ["Kitex", "多 Service", "单 Server 多 Service", "gRPC", "thrift", "protobuf"] description: Kitex 支持在一个 Server 上注册多个 Service 。 --- @@ -23,12 +24,13 @@ description: Kitex 支持在一个 Server 上注册多个 Service 。 1. 将客户端升级到 Kitex 版本 >= v0.9.0 2. 对于 Kitex thrift 和 protobuf(non-streaming)的API: - 1. 使用 TTHeader 作为传输协议`client.WithTransportProtocol(transport.TTHeader)` - 2. 在客户端添加以下选项:`client.WithMetaHandler(transmeta.ClientTTHeaderHandler)` + 1. 使用 TTHeader 作为传输协议`client.WithTransportProtocol(transport.TTHeader)` + 2. 在客户端添加以下选项:`client.WithMetaHandler(transmeta.ClientTTHeaderHandler)` ### 服务器端 #### 准备工作 + 请使用 Kitex 命令工具 ( >= v0.9.0 ) 为每个 Service 生成代码。更多详情,请参考[代码生成工具](/zh/docs/kitex/tutorials/code-gen/code_generation/)。 (注:对于使用 gRPC 多服务功能的用户,从 v0.8.0 版本开始,服务注册方面的使用方法略有变化,请升级您的 Kitex 命令工具至 v0.9.0+。更多详情,请参阅“[创建 Server 并在 Server 上注册您的 Service](/zh/docs/kitex/tutorials/advanced-feature/multi_service/#创建-server-并在-server-上注册您的-service)”部分。) @@ -50,7 +52,9 @@ kitex_gen |_ serviceb.go |_ ... ``` + 您可以在每个 Service 的`server.go`中看到`RegisterService`函数。 + ```golang func RegisterService(svr server.Server, handler XXX, opts ...server.RegisterOption) error { if err := svr.RegisterService(serviceInfo(), handler, opts...); err != nil { @@ -61,6 +65,7 @@ func RegisterService(svr server.Server, handler XXX, opts ...server.RegisterOpti ``` ### 创建 Server 并在 Server 上注册您的 Service + 在 Server 上注册 Service 是一个简单的过程。 首先,创建一台 Server 。然后,通过在您生成的代码中调用`RegisterService`函数,即可注册 Service 。 @@ -72,20 +77,20 @@ package main import ( "github.com/cloudwego/kitex/pkg/server" - + servicea "your_servicea_kitex_gen_path" serviceb "your_serviceb_kitex_gen_path" -) +) func main() { - // 通过调用 server.NewServer 创建 Server + // 通过调用 server.NewServer 创建 Server svr := server.NewServer(your_server_option) // 在 Server 上注册多 Service err := servicea.RegisterService(svr, new(ServiceAImpl)) err = serviceb.RegisterService(svr, new(ServiceBImpl)) - + err = svr.Run() - + if err != nil { logs.Error("%s", err.Error()) } @@ -94,6 +99,7 @@ func main() { ``` ### 备用 Service + 假设 Service 之间有相同的命名方法。 ```thrift @@ -128,13 +134,13 @@ Response sameNamedMethod(1: Request req) ```golang func main() { - // 通过调用 server.NewServer 创建 Server + // 通过调用 server.NewServer 创建 Server svr := server.NewServer(your_server_option) - // 在 Server 上注册多 Service - // servicea 将成为备用 Service + // 在 Server 上注册多 Service + // servicea 将成为备用 Service servicea.RegisterService(svr, new(ServiceAImpl), server.WithFallbackService()) serviceb.RegisterService(svr, new(ServiceBImpl)) - + err := svr.Run() if err != nil { logs.Error("%s", err.Error()) @@ -150,6 +156,7 @@ func main() { 但在使用此选项时,必须注意以下事项: 当`server.WithRefuseTrafficWithoutServiceName`选项启用后,如果客户端的设置没有满足[客户端使用方法](/zh/docs/kitex/tutorials/advanced-feature/multi_service/#客户端)一节中的任何条件,则会出现错误消息: + > no service name while the server has WithRefuseTrafficWithoutServiceName option enabled ### 如何不回退到备用 Service(不依赖方法名称来查找服务) @@ -180,19 +187,20 @@ method, ok := kitexutil.GetMethod(ctx) options = append(options, server.WithMiddleware(yourMiddleware)) svr := server.NewServer(options...) ``` + 您可以使用前述方法来获得每个请求的 service/method,以便区分处理。 ### 区分流式/非流式方法 确定请求是否具有流式处理底层协议的推荐方法是检查请求/响应参数的类型: -| | **客户端中间件** | **服务端中间件** | -|-------------------------------------|--------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------| -| **Bidirectional**
**(gRPC)** | - request: `interface{}` = nil
- response: *streaming.Result | - request: *streaming.Args
- response: `interface{}` = nil | -| **Client Streaming**
**(gRPC)** | - request: interface{} = nil
- response: *streaming.Result | - request: *streaming.Args
- response: `interface{}` = nil | -| **Server Streaming**
**(gRPC)** | - request: `interface{}` = nil
- response: *streaming.Result | - request: *streaming.Args
- response: `interface{}` = nil | -| **Unary (gRPC)** | - request: *kitex_gen/some_pkg.${svc}${method}Args
- response: *kitex_gen/some_pkg.${svc}${method}Result | - request: *streaming.Args
- response: `interface{}` = nil
注意:该选项自 v0.9.0 起可用:`server.WithCompatibleMiddlewareForUnary()` 使其与 PingPong API 相同 | -| **PingPong API (KitexPB)** | - request: *kitex_gen/some_pkg.${svc}${method}Args
- response: *kitex_gen/some_pkg.${svc}${method}Result | - request: *kitex_gen/some_pkg.${svc}${method}Args
- response: *kitex_gen/some_pkg.${svc}${method}Result | +| | **客户端中间件** | **服务端中间件** | +| ----------------------------------- | ------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| **Bidirectional**
**(gRPC)** | - request: `interface{}` = nil
- response: \*streaming.Result | - request: \*streaming.Args
- response: `interface{}` = nil | +| **Client Streaming**
**(gRPC)** | - request: interface{} = nil
- response: \*streaming.Result | - request: \*streaming.Args
- response: `interface{}` = nil | +| **Server Streaming**
**(gRPC)** | - request: `interface{}` = nil
- response: \*streaming.Result | - request: \*streaming.Args
- response: `interface{}` = nil | +| **Unary (gRPC)** | - request: *kitex_gen/some_pkg.${svc}${method}Args
- response: *kitex_gen/some_pkg.${svc}${method}Result | - request: \*streaming.Args
- response: `interface{}` = nil
注意:该选项自 v0.9.0 起可用:`server.WithCompatibleMiddlewareForUnary()` 使其与 PingPong API 相同 | +| **PingPong API (KitexPB)** | - request: *kitex_gen/some_pkg.${svc}${method}Args
- response: *kitex_gen/some_pkg.${svc}${method}Result | - request: *kitex_gen/some_pkg.${svc}${method}Args
- response: *kitex_gen/some_pkg.${svc}${method}Result | **注意:** Kitex 服务器支持对传入请求的协议探测,对于 gRPC/Protobuf Unary 方法,它同时接受 gRPC 请求和 KitexProtobuf(TTHeader + Pure Protobuf Payload) 请求, 因此 **仅依靠 RPCInfo 中的方法名称可能并不准确**。 @@ -241,7 +249,7 @@ func serverMWForIdentifyStreamingRequests(next endpoint.Endpoint) endpoint.Endpo - 所有 Service(Combine Service 和被合并的每个 Service)的代码都会生成。 - Service 的所有方法名称必须是唯一的。 - 一个 Server 上只能注册一个 Service (即 combine service)。 - 否则,您将收到一条错误消息,提示您“在注册 Combine Service 时只能注册一个 Service”。 + 否则,您将收到一条错误消息,提示您“在注册 Combine Service 时只能注册一个 Service”。 - 单 Server 多 Service(即 Multiple Services,**更推荐使用**) - 每个 Service 的代码都会单独生成。 - Service 之间的方法名称可以相同,但也有一些限制。请选一个解决方案: @@ -251,7 +259,8 @@ func serverMWForIdentifyStreamingRequests(next endpoint.Endpoint) endpoint.Endpo ### 2. Service 注册失败的原因? - 可能的原因如下: - - 当您注册的 Service 之间具有相同名称的方法时,未指定备用 Service。请指定备用 Service 。 - - 您正在尝试在 Server 上同时注册 Combine Service 和其他 Service 。 +可能的原因如下: + +- 当您注册的 Service 之间具有相同名称的方法时,未指定备用 Service。请指定备用 Service 。 +- 您正在尝试在 Server 上同时注册 Combine Service 和其他 Service 。 请注意,Combine Service 只能在 Server 上单独注册。如果您还想注册其他 Service ,则需要将这些 Service 合并到 Combine Service 中,或者在不使用 Combine Service 的情况下单独注册每个 Service 。 diff --git a/content/zh/docs/kitex/Tutorials/advanced-feature/xds.md b/content/zh/docs/kitex/Tutorials/advanced-feature/xds.md index a333f0693c..64ebcd49f4 100644 --- a/content/zh/docs/kitex/Tutorials/advanced-feature/xds.md +++ b/content/zh/docs/kitex/Tutorials/advanced-feature/xds.md @@ -13,27 +13,28 @@ Kitex 通过外部扩展 [kitex-contrib/xds](https://github.com/kitex-contrib/xd ## 已支持的功能 -* 服务发现 -* 服务路由:当前支持`method` 的精确匹配和 `header` 的精确匹配、前缀匹配、正则匹配。 - * [HTTP route configuration](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/http/http_routing#arch-overview-http-routing): 通过 [VirtualService](https://istio.io/latest/docs/reference/config/networking/virtual-service/) 进行配置 - * [ThriftProxy](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto): 通过 [EnvoyFilter](https://istio.io/latest/docs/reference/config/networking/envoy-filter/) 进行配置。 -* 超时: - * `HTTP route configuration` 内包含的配置,同样通过 VirtualService 来配置。 +- 服务发现 +- 服务路由:当前支持`method` 的精确匹配和 `header` 的精确匹配、前缀匹配、正则匹配。 + - [HTTP route configuration](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/http/http_routing#arch-overview-http-routing): 通过 [VirtualService](https://istio.io/latest/docs/reference/config/networking/virtual-service/) 进行配置 + - [ThriftProxy](https://www.envoyproxy.io/docs/envoy/latest/api-v3/extensions/filters/network/thrift_proxy/v3/thrift_proxy.proto): 通过 [EnvoyFilter](https://istio.io/latest/docs/reference/config/networking/envoy-filter/) 进行配置。 +- 超时: + - `HTTP route configuration` 内包含的配置,同样通过 VirtualService 来配置。 ## 开启方式 + 开启的步骤分为两个部分:1. xDS 模块的初始化和 2. Kitex Client/Server 的 Option 配置。 ### xDS 模块 -调用 `xds.Init()` 便可开启对 xDS 模块的初始化,其中包括 `xdsResourceManager` - 负责 xDS 资源的管理,`xdsClient` - 负责与控制面进行交互。 +调用 `xds.Init()` 便可开启对 xDS 模块的初始化,其中包括 `xdsResourceManager` - 负责 xDS 资源的管理,`xdsClient` - 负责与控制面进行交互。 #### Bootstrap -`xdsClient` 负责与控制面(例如 Istio)交互,以获得所需的 xDS 资源。在初始化时,需要读取环境变量用于构建 node 标识。所以,需要在 K8S 的容器配置文件 `spec.containers.env` 部分加入以下几个环境变量。 +`xdsClient` 负责与控制面(例如 Istio)交互,以获得所需的 xDS 资源。在初始化时,需要读取环境变量用于构建 node 标识。所以,需要在 K8S 的容器配置文件 `spec.containers.env` 部分加入以下几个环境变量。 -* `POD_NAMESPACE`: 当前 pod 所在的 namespace。 -* `POD_NAME`: pod 名。 -* `INSTANCE_IP`: pod 的 ip。 +- `POD_NAMESPACE`: 当前 pod 所在的 namespace。 +- `POD_NAME`: pod 名。 +- `INSTANCE_IP`: pod 的 ip。 在需要使用 xDS 功能的容器配置中加入以下定义即可: @@ -53,10 +54,11 @@ valueFrom: ``` ### Kitex 客户端 + 目前,我们仅在 Kitex 客户端提供 xDS 的支持。 -想要使用支持 xds 的 Kitex 客户端,请在构造 Kitex Client 时将 `destService` 指定为目标服务的 URL,并添加一个选项 `WithXDSSuite`。 +想要使用支持 xds 的 Kitex 客户端,请在构造 Kitex Client 时将 `destService` 指定为目标服务的 URL,并添加一个选项 `WithXDSSuite`。 -* 构造一个 `xds.ClientSuite`,需要包含用于服务路由的`RouteMiddleware`中间件和用于服务发现的 `Resolver`。将该 ClientSuite 传入`WithXDSSuite` option 中. +- 构造一个 `xds.ClientSuite`,需要包含用于服务路由的`RouteMiddleware`中间件和用于服务发现的 `Resolver`。将该 ClientSuite 传入`WithXDSSuite` option 中. ``` // import "github.com/cloudwego/kitex/pkg/xds" @@ -67,7 +69,7 @@ client.WithXDSSuite(xds.ClientSuite{ }), ``` -* 目标服务的 URL 格式应遵循 [Kubernetes](https://kubernetes.io/) 中的格式: +- 目标服务的 URL 格式应遵循 [Kubernetes](https://kubernetes.io/) 中的格式: ``` ..svc.cluster.local: @@ -81,8 +83,9 @@ client.WithXDSSuite(xds.ClientSuite{ 我们可以通过 Istio 中的 [VirtualService](https://istio.io/latest/docs/reference/config/networking/virtual-service/) 来定义流量路由配置。 下面的例子表示 tag 满足以下条件时请求会被路由到 `kitex-server` 的 `v1` 子集群: -- `stage` 精确匹配到 `canary` -- `userid` 前缀匹配到 `2100` + +- `stage` 精确匹配到 `canary` +- `userid` 前缀匹配到 `2100` - `env` 正则匹配到 `[dev|sit]` ``` @@ -115,7 +118,7 @@ spec: 为了匹配 VirtualService 中定义的规则,我们可以使用`client.WithTag(key, val string)`或者`callopt.WithTag(key, val string)`来指定标签,这些标签将用于匹配规则。 -* 比如:将 key 和 value 设置为“stage”和“canary”,以匹配 VirtualService 中定义的上述规则。 +- 比如:将 key 和 value 设置为“stage”和“canary”,以匹配 VirtualService 中定义的上述规则。 ``` client.WithTag("stage", "canary") @@ -123,11 +126,12 @@ callopt.WithTag("stage", "canary") ``` #### 基于 method 的路由匹配 + 同上,利用 Istio 中的 [VirtualService](https://istio.io/latest/docs/reference/config/networking/virtual-service/) 来定义流量路由配置。 下面的例子表示,对于 method 等于 SayHello 的请求,路由到 `kitex-server` 的 `v1` 子集群。 需要注意的是,在定义规则时需要包含 package name 和 service name,对应 thrift idl 内的 `namespace` 和 `service`。 -* uri: `/${PackageName}.${ServiceName}/${MethodName}` +- uri: `/${PackageName}.${ServiceName}/${MethodName}` ``` apiVersion: networking.istio.io/v1alpha3 @@ -152,6 +156,7 @@ spec: ``` ## 示例 + 完整的客户端用法如下: ``` @@ -190,7 +195,9 @@ func main() { 更详细的例子可以参考该仓库:[kitex-proxyless-example](https://github.com/cloudwego/kitex-examples/tree/main/proxyless). ## 当前版本的不足 + ### mTLS + 目前不支持 mTLS。 请通过配置 PeerAuthentication 以禁用 mTLS。 ``` @@ -205,9 +212,11 @@ spec: ``` ### 有限的服务治理功能 + 当前版本仅支持客户端通过 xDS 进行服务发现、流量路由和超时配置。 xDS 所支持的其他服务治理功能,包括负载均衡、限流和重试等,将在未来补齐。 ## 依赖 + Kitex >= v0.4.0 diff --git a/content/zh/docs/kitex/Tutorials/basic-feature/_index.md b/content/zh/docs/kitex/Tutorials/basic-feature/_index.md index 88161a62b1..6d7383ace9 100644 --- a/content/zh/docs/kitex/Tutorials/basic-feature/_index.md +++ b/content/zh/docs/kitex/Tutorials/basic-feature/_index.md @@ -4,5 +4,4 @@ linkTitle: "基本特性" weight: 1 date: 2021-08-26 description: > - ---- \ No newline at end of file +--- diff --git a/content/zh/docs/kitex/Tutorials/basic-feature/acquire_rpcinfo.md b/content/zh/docs/kitex/Tutorials/basic-feature/acquire_rpcinfo.md index ae764b9d36..043bb4f668 100644 --- a/content/zh/docs/kitex/Tutorials/basic-feature/acquire_rpcinfo.md +++ b/content/zh/docs/kitex/Tutorials/basic-feature/acquire_rpcinfo.md @@ -14,14 +14,14 @@ Kitex 的 RPCInfo 的生命周期默认是从请求开始到请求返回(性 同步的使用方式是指用户没有在新起的 Goroutine 里获取 RPCInfo。 -| **获取的信息** | **Kitex 获取方式** | -| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| 获取调用方的 Service | caller, ok := kitexutil.GetCaller(ctx) | -| 获取 RPC 方法名 | method, ok := kitexutil.GetMethod(ctx) | -| 获取调用方的请求地址 | cluster, ok := kitexutil.GetCallerAddr(ctx) | -| 获取 IDL 里定义的 ServiceName | svcName, ok := kitexutil.GetIDLServiceName(ctx) | -| 获取调用方的 handler 接口名 | callerMethod, ok := kitexutil.GetCallerHandlerMethod(ctx)
只有调用方也是 Kitex Server 才默认有这个信息,或者调用方主动将 K_METHOD 写入 context.Context 中,Kitex 会获取该信息传输给服务端。 | -| 获取传输协议 | tp, ok := kitexutil.GetTransportProtocol(ctx) | +| **获取的信息** | **Kitex 获取方式** | +| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| 获取调用方的 Service | caller, ok := kitexutil.GetCaller(ctx) | +| 获取 RPC 方法名 | method, ok := kitexutil.GetMethod(ctx) | +| 获取调用方的请求地址 | cluster, ok := kitexutil.GetCallerAddr(ctx) | +| 获取 IDL 里定义的 ServiceName | svcName, ok := kitexutil.GetIDLServiceName(ctx) | +| 获取调用方的 handler 接口名 | callerMethod, ok := kitexutil.GetCallerHandlerMethod(ctx)
只有调用方也是 Kitex Server 才默认有这个信息,或者调用方主动将 K_METHOD 写入 context.Context 中,Kitex 会获取该信息传输给服务端。 | +| 获取传输协议 | tp, ok := kitexutil.GetTransportProtocol(ctx) | | 调用端获取请求的服务端的地址 | ctx = metainfo.WithBackwardValues(ctx)
// 先设置 ctx,再执行 RPC 调用 ...err, resp := cli.YourMethod(ctx, req)rip, ok := metainfo.GetBackwardValue(ctx, consts.RemoteAddr)
注意:不适用于 oneway 方法 | ### 1.2 异步使用方式 @@ -36,11 +36,11 @@ import ( "github.com/cloudwego/kitex/pkg/utils/kitexutil" ) // this creates a read-only copy of `ri` and attaches it to the new context -ctx2 := rpcinfo.FreezeRPCInfo(ctx) +ctx2 := rpcinfo.FreezeRPCInfo(ctx) go func(ctx context.Context) { // ... ri := rpcinfo.GetRPCInfo(ctx) // OK - + // eg: get client psm // caller, ok := kitexutil.GetCaller(ctx) //... diff --git a/content/zh/docs/kitex/Tutorials/basic-feature/bizstatuserr.md b/content/zh/docs/kitex/Tutorials/basic-feature/bizstatuserr.md index 6f98440cca..d4947c2237 100644 --- a/content/zh/docs/kitex/Tutorials/basic-feature/bizstatuserr.md +++ b/content/zh/docs/kitex/Tutorials/basic-feature/bizstatuserr.md @@ -10,6 +10,7 @@ description: "Kitex 自 v0.4.3 版本提供了业务自定义异常功能,本 但业务错误属于业务逻辑层面,在 RPC 层面其实是请求成功。服务监控建议对于 RPC 错误上报为请求失败,而业务层面错误,上报为请求成功,而使用额外的 biz_status_code 字段上报业务异常状态码。该能力对于工程实践具有一定的价值。 ## BizStatusError 接口定义 + 内置 `BizStatusErrorIface` 提供自定义异常接口,框架同时提供默认实现,用户也可以自定义实现。gRPC 用户自定义的 Error 可同时实现 `GRPCStatusIface` ,以便复用 Status 的 Detail 用于透传更丰富的业务信息。 ```go @@ -52,7 +53,9 @@ bizErr, isBizErr := kerrors.FromBizStatusError(err) ``` 如需额外传递 gRPC Detail,可以使用 `NewGRPCBizStatusError` 或 `NewGRPCBizStatusErrorWithExtra` 来构造异常: + > 注:如无需传递 gRPC Detail,gRPC 用户仍可以使用 `NewBizStatusError` 或 `NewBizStatusErrorWithExtra`. + ```go // Server side func (*Handler) Serve(ctx, Request) (Response, error) { @@ -92,6 +95,7 @@ bizErr := rpcinfo.GetRPCInfo(ctx).Invocation().BizStatusErr() ``` 如果要在中间件中返回 BizStatusError,可以用如下方式: + ```go ri := rpcinfo.GetRPCInfo(ctx) if setter, ok := ri.Invocation().(rpcinfo.InvocationSetter); ok { @@ -100,8 +104,8 @@ if setter, ok := ri.Invocation().(rpcinfo.InvocationSetter); ok { } ``` - ## 框架实现 + 依赖传输协议透传自定义异常的错误码和错误信息,Thrift 和 Kitex Protobuf 依赖 TTHeader,Kitex gRPC 依赖 HTTP2。 - Thrift:使用 TTHeader @@ -125,4 +129,3 @@ gRPC 的 RPC 异常是通过 HTTP2 Header 传递的,statusCode 和 statusMessa 为尽量做到前向兼容,同时区分 gRPC 的 RPC 异常,在其现有基础上额外增加 biz-status 和 biz-extra 字段,分别对应于 `BizStatusErrorIface` 的 errorCode 和 extra,而 message 则复用 grpc-message。 在 server 返回自定义异常时,将 grpc-status 编码为业务异常实现的 `GRPCStatusIface` 接口中的 statusCode 或 `codes.Internal`,同时编码 biz-status。这样,上游收到响应后,发现设置了 biz-status header, 即可将错误转换为 `BizStatusErrorIface` 返回给 client handler。即使上游不支持自定义异常,也能相对正确地处理 server 返回的 error,只不过丢失了识别业务异常的能力。 - diff --git a/content/zh/docs/kitex/Tutorials/basic-feature/connection_type.md b/content/zh/docs/kitex/Tutorials/basic-feature/connection_type.md index e945838464..85e8d76226 100644 --- a/content/zh/docs/kitex/Tutorials/basic-feature/connection_type.md +++ b/content/zh/docs/kitex/Tutorials/basic-feature/connection_type.md @@ -46,6 +46,7 @@ xxxCli := xxxservice.NewClient("destServiceName", client.WithLongConnection(conn - `MinIdlePerAddress`(Kitex >= v0.4.3) - 表示对每个后端实例维护的最小空闲连接数,这部分连接即使空闲时间超过 `MaxIdleTimeout` 也不会被清理。 - 当前版本的`MinIdlePerAddress`的值不能超过5。 + ### 实现 长连接池的实现方案是每个 address 对应一个连接池,池的大小为 `MaxIdlePerAddress`。 @@ -67,16 +68,16 @@ xxxCli := xxxservice.NewClient("destServiceName", client.WithLongConnection(conn 下面是参数设置的一些建议: - `MaxIdlePerAddress` 表示池化的连接数量,最小为 1,否则长连接会退化为短连接 - - 具体的值与每个目标地址的吞吐量有关,近似的估算公式为:`MaxIdlePerAddress = qps_per_dest_host*avg_response_time_sec ` - - 举例如下,假设每个请求的响应时间为 100ms,平摊到每个下游地址的请求为 100QPS,该值建议设置为10,因为每条连接每秒可以处理 10 个请求, 100QPS 则需要 10 个连接进行处理 - - 在实际场景中,也需要考虑到流量的波动。需要特别注意的是,即 MaxIdleTimeout 内该连接没有被使用则会被回收 - - 总而言之,该值设置过大或者过小,都会导致连接复用率低,长连接退化为短连接 + - 具体的值与每个目标地址的吞吐量有关,近似的估算公式为:`MaxIdlePerAddress = qps_per_dest_host*avg_response_time_sec ` + - 举例如下,假设每个请求的响应时间为 100ms,平摊到每个下游地址的请求为 100QPS,该值建议设置为10,因为每条连接每秒可以处理 10 个请求, 100QPS 则需要 10 个连接进行处理 + - 在实际场景中,也需要考虑到流量的波动。需要特别注意的是,即 MaxIdleTimeout 内该连接没有被使用则会被回收 + - 总而言之,该值设置过大或者过小,都会导致连接复用率低,长连接退化为短连接 - `MinIdlePerAddress` - 假设有周期性请求的场景,且周期大于 MaxIdleTimeout,设置此参数可避免每次新建连接。 - 与 MaxIdlePerAddress 类似,可根据请求的响应时间和 qps 进行设置。 - 以最大值5个连接为例,假设每个请求的响应时间为100ms,在不新建连接的情况下可以处理 50QPS。 - `MaxIdleGlobal` 表示总的空闲连接数应大于 `下游目标总数*MaxIdlePerAddress`,超出部分是为了限制未能从连接池中获取连接而主动新建连接的总数量 - - 注意:该值存在的价值不大,建议设置为一个较大的值,在后续版本中考虑废弃该参数并提供新的接口 + - 注意:该值存在的价值不大,建议设置为一个较大的值,在后续版本中考虑废弃该参数并提供新的接口 - `MaxIdleTimeout` 表示连接空闲时间,由于 server 在 10min 内会清理不活跃的连接,因此 client 端也需要及时清理空闲较久的连接,避免使用无效的连接,该值在下游也为 Kitex 时不可超过 10min ## 连接多路复用 @@ -105,7 +106,6 @@ xxxCli := xxxservice.NewClient("destServiceName", client.WithLongConnection(conn xxxCli := NewClient("destServiceName", client.WithMuxConnection(1)) ``` - ## 状态监控 连接池定义了 `Reporter` 接口,用于连接池状态监控,例如长连接的复用率。 diff --git a/content/zh/docs/kitex/Tutorials/basic-feature/message_type.md b/content/zh/docs/kitex/Tutorials/basic-feature/message_type.md index b8d2d1559a..fd7dc2d8e1 100644 --- a/content/zh/docs/kitex/Tutorials/basic-feature/message_type.md +++ b/content/zh/docs/kitex/Tutorials/basic-feature/message_type.md @@ -10,11 +10,11 @@ description: Kitex 支持 PingPong、Oneway、Streaming 消息类型。 目前 Kitex 支持的消息类型、编解码协议和传输协议 -| 消息类型 | 编码协议 | 传输协议 | -|--------|-------|-------------------------------------------------------| -|PingPong|Thrift / Protobuf| [TTHeader](../../../reference/transport_protocol_ttheader) / HTTP2(gRPC) | -|Oneway|Thrift| [TTHeader](../../../reference/transport_protocol_ttheader) | -|Streaming|Protobuf| HTTP2(gRPC) | +| 消息类型 | 编码协议 | 传输协议 | +| --------- | ----------------- | ------------------------------------------------------------------------ | +| PingPong | Thrift / Protobuf | [TTHeader](../../../reference/transport_protocol_ttheader) / HTTP2(gRPC) | +| Oneway | Thrift | [TTHeader](../../../reference/transport_protocol_ttheader) | +| Streaming | Protobuf | HTTP2(gRPC) | - PingPong:客户端发起一个请求后会等待一个响应才可以进行下一次请求 - Oneway:客户端发起一个请求后不等待一个响应 @@ -107,7 +107,7 @@ import ( "xx/echo" "xx/echo/echoservice" - + "github.com/cloudwego/kitex/client" ) @@ -122,7 +122,7 @@ func main() { if err != nil { panic(err) } - + fmt.Println(resp.Msg) // resp.Msg == "world" } @@ -140,7 +140,7 @@ import ( "xx/echo" "xx/echo/echoservice" - + "github.com/cloudwego/kitex/client" ) @@ -164,9 +164,9 @@ func main() { Kitex 支持两种承载 Protobuf 负载的协议: - Kitex Protobuf - - 只支持 PingPong,若 IDL 定义了 stream 方法,将默认使用 gRPC 协议 + - 只支持 PingPong,若 IDL 定义了 stream 方法,将默认使用 gRPC 协议 - gRPC 协议 - - 可以与 gRPC 互通,与 gRPC service 定义相同,支持 Unary(PingPong)、 Streaming 调用 + - 可以与 gRPC 互通,与 gRPC service 定义相同,支持 Unary(PingPong)、 Streaming 调用 ### Example @@ -220,7 +220,7 @@ import ( "log" "time" "context" - + "xx/echo" "xx/echo/echoservice" } @@ -283,7 +283,7 @@ func (handler) BidiSideStreaming(stream echo.EchoService_BidiSideStreamingServer time.Sleep(time.Second) } }() - + err = <-errChan cancel() return err @@ -291,9 +291,9 @@ func (handler) BidiSideStreaming(stream echo.EchoService_BidiSideStreamingServer func main() { svr := echoservice.NewServer(new(handler)) - + err := svr.Run() - + if err != nil { log.Println(err.Error()) } @@ -310,10 +310,10 @@ package main import ( "context" "time" - + "xx/echo" "xx/echo/echoservice" - + "github.com/cloudwego/kitex/client" } @@ -346,10 +346,10 @@ import ( "context" "log" "time" - + "xx/echo" "xx/echo/echoservice" - + "github.com/cloudwego/kitex/client" } @@ -385,10 +385,10 @@ import ( "context" "log" "time" - + "xx/echo" "xx/echo/echoservice" - + "github.com/cloudwego/kitex/client" } diff --git a/content/zh/docs/kitex/Tutorials/basic-feature/protocol/_index.md b/content/zh/docs/kitex/Tutorials/basic-feature/protocol/_index.md index ac56e3e370..110f1288dc 100644 --- a/content/zh/docs/kitex/Tutorials/basic-feature/protocol/_index.md +++ b/content/zh/docs/kitex/Tutorials/basic-feature/protocol/_index.md @@ -4,5 +4,4 @@ linkTitle: "协议" weight: 2 date: 2024-01-06 description: > - --- diff --git a/content/zh/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/_index.md b/content/zh/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/_index.md index 318315e3e1..8cd754f55e 100644 --- a/content/zh/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/_index.md +++ b/content/zh/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/_index.md @@ -2,6 +2,6 @@ title: "序列化协议" date: 2024-01-06 weight: 2 -keywords: [ "Kitex", "序列化", "编解码", "Thrift", "Protobuf" ] +keywords: ["Kitex", "序列化", "编解码", "Thrift", "Protobuf"] description: Kitex 支持 Thrift 和 Protobuf 的编解码。 --- diff --git a/content/zh/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/binary.md b/content/zh/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/binary.md index f56f27aa53..484c488082 100644 --- a/content/zh/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/binary.md +++ b/content/zh/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/binary.md @@ -2,7 +2,7 @@ title: "Binary" date: 2024-01-06 weight: 1 -keywords: [ "Kitex", "序列化", "Binary", "Thrift" ] +keywords: ["Kitex", "序列化", "Binary", "Thrift"] description: Kitex 使用 Binary 协议序列化。 --- diff --git a/content/zh/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/hessian2.md b/content/zh/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/hessian2.md index bb4238031f..f4cba34542 100644 --- a/content/zh/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/hessian2.md +++ b/content/zh/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/hessian2.md @@ -2,7 +2,7 @@ title: "Hessian2" date: 2024-01-06 weight: 3 -keywords: [ "Kitex", "序列化", "Hessian2" ] +keywords: ["Kitex", "序列化", "Hessian2"] description: Kitex 使用 Hessian2 协议序列化。 --- @@ -36,7 +36,6 @@ Hessian2 协议用于 Kitex 与 Dubbo 互通,该协议并非 Kitex 核心支 ) ``` - #### 服务端 - **生成代码** diff --git a/content/zh/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/protobuf.md b/content/zh/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/protobuf.md index 85e0e45b48..3acb3fca82 100644 --- a/content/zh/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/protobuf.md +++ b/content/zh/docs/kitex/Tutorials/basic-feature/protocol/serialization-protocol/protobuf.md @@ -2,7 +2,7 @@ title: "Protobuf" date: 2024-01-06 weight: 2 -keywords: [ "Kitex", "序列化", "Protobuf" ] +keywords: ["Kitex", "序列化", "Protobuf"] description: Kitex 使用 Protobuf 协议序列化。 --- diff --git a/content/zh/docs/kitex/Tutorials/basic-feature/protocol/transport-streaming/_index.md b/content/zh/docs/kitex/Tutorials/basic-feature/protocol/transport-streaming/_index.md index b53e6d09fa..0626ab5ca7 100644 --- a/content/zh/docs/kitex/Tutorials/basic-feature/protocol/transport-streaming/_index.md +++ b/content/zh/docs/kitex/Tutorials/basic-feature/protocol/transport-streaming/_index.md @@ -4,5 +4,4 @@ linkTitle: "Streaming 传输" weight: 3 date: 2024-03-06 description: > - --- diff --git a/content/zh/docs/kitex/Tutorials/basic-feature/protocol/transport-streaming/thrift_streaming.md b/content/zh/docs/kitex/Tutorials/basic-feature/protocol/transport-streaming/thrift_streaming.md index 9a53406661..74bd1f4140 100644 --- a/content/zh/docs/kitex/Tutorials/basic-feature/protocol/transport-streaming/thrift_streaming.md +++ b/content/zh/docs/kitex/Tutorials/basic-feature/protocol/transport-streaming/thrift_streaming.md @@ -2,7 +2,7 @@ title: "Thrift Streaming" date: 2024-03-06 weight: 2 -keywords: [ "Kitex", "Streaming", "Thrift"] +keywords: ["Kitex", "Streaming", "Thrift"] description: 本文介绍如何在 Thrift IDL 里定义并使用 Streaming API。 --- @@ -17,6 +17,7 @@ description: 本文介绍如何在 Thrift IDL 里定义并使用 Streaming API #### PingPong API (KitexThrift) Kitex 默认的 Thrift API 模式: + - 只支持 PingPong,不支持 Streaming API - Thrift Payload 可能包含前缀 [TTHeader](/zh/docs/kitex/reference/transport_protocol_ttheader/)、[Framed](https://github.com/apache/thrift/blob/0.13.0/doc/specs/thrift-rpc.md#framed-vs-unframed-transport),或二者的组合(TTHeader + Framed + Payload) @@ -33,12 +34,15 @@ Kitex 默认的 Thrift API 模式: Streaming API 分成三类(参考 [gRPC core concepts](https://grpc.io/docs/what-is-grpc/core-concepts/))。 ##### Server Streaming + Client 发送一个 Message,Server 返回多个 Message,然后关闭 Stream。 ##### Client Streaming + Client 发送多个 Message,Server 返回一个 Message,然后关闭 Stream。 ##### Bidirectional Streaming + Client/Server 的收、发均为独立的流,可根据业务需求,按任意顺序执行 Recv、Send。 ## Streaming over HTTP2 @@ -61,7 +65,7 @@ go install github.com/cloudwego/kitex/tool/cmd/kitex@latest Kitex 通过 `streaming.mode` 注解判断方法的 Streaming 类型。 | 取值 | 含义 | 说明 | -|---------------|-------------------------|-----------------------------------------------------------------------------| +| ------------- | ----------------------- | --------------------------------------------------------------------------- | | bidirectional | Bidirectional streaming | 收、发是独立的流,业务可以按需处理 | | client | Client Side Streaming | Client 发送多个 Message,Server 返回一个 Message | | server | Server Side Streaming | Client 发送一个 Message,Server 返回多个 Message | @@ -69,11 +73,12 @@ Kitex 通过 `streaming.mode` 注解判断方法的 Streaming 类型。 | (其他值) | 无效,报错 | | 注意: + 1. Streaming API 有且只有 一个 request 和一个 response,否则 Kitex 会报错 -2. **Kitex 支持 在同一个 Service 里同时定义 PingPong API(非Streaming) 和 Streaming API** - - 1. Server 会自动探测协议、路由请求 - +2. **Kitex 支持 在同一个 Service 里同时定义 PingPong API(非Streaming) 和 Streaming API** + + 1. Server 会自动探测协议、路由请求 + 3. 不建议使用 Unary over HTTP2(性能损失较大),建议使用 PingPong API(KitexThrift ) 4. streaming.mode 只能出现最多一次(不支持指定多个值),否则 Kitex 会报错 @@ -103,6 +108,7 @@ service TestService { #### 生成项目脚手架 对于新增项目,先初始化项目目录: + ```bash mkdir demo-project && cd demo-project @@ -111,12 +117,15 @@ go mod init $module ``` Kitex 的使用与原 KitexThrift 项目一致,例如: + ```bash kitex -module $module -service demo-server api.thrift ``` + 注意:对于现有项目,也需要重新生成代码,并更新 go.mod 里的 Kitex 版本 然后执行: + ```bash go mod tidy ``` @@ -126,6 +135,7 @@ go mod tidy ##### 创建 Stream Client(调用端) 注意: + - 对于 Streaming API,需要创建 **StreamClient** - 创建 StreamClient 时应指定 `streamclient.Option` (不是 client.Option) - 调用 Streaming API 时应指定 `streamcall.Option` (不是 callopt.Option) @@ -149,14 +159,16 @@ stream, err := streamClient.Echo(ctx, streamcall.WithHostPorts("127.0.0.1:8888") ##### Bidirectional Streaming API 注意: + 1. 请求双方应协商好关闭 Stream 的条件,否则可能导致双方都一直等待下去(goroutine 泄漏) 2. 示例展示了全双工模式(Recv 和 Send 完全独立) - - 1. 可按业务需求调整处理逻辑,例如(半双工模式)Server 总是在收到一个 Message 处理完再将结果发送给 Client + + 1. 可按业务需求调整处理逻辑,例如(半双工模式)Server 总是在收到一个 Message 处理完再将结果发送给 Client ###### Server Handler 注意: + 1. method handler 结束后,Kitex 会写 Trailer Frame(等同于关闭 stream);业务代码不需要主动调用 `stream.Close()` 2. 新启动的 goroutine 应当自行 recover 3. 「Recv 返回 `io.EOF`」表示 client 已发送结束 @@ -166,12 +178,13 @@ stream, err := streamClient.Echo(ctx, streamcall.WithHostPorts("127.0.0.1:8888") ###### Stream Client 注意: + 1. 新启动的 goroutine 应当自行 recover 2. Client 发送结束后应及时调用 stream.Close() 告知 server 3. 「Recv 返回 `io.EOF` 或其他 non-nil error」表示 server 已发送结束(或出错) - - 1. 此时 Kitex 才会记录 RPCFinish 事件(Tracer 依赖该事件) - 2. 如 client 和 server 约定了其他结束方式,应主动调用 streaming.FinishStream(stream, err) 记录 RPCFinish 事件 + + 1. 此时 Kitex 才会记录 RPCFinish 事件(Tracer 依赖该事件) + 2. 如 client 和 server 约定了其他结束方式,应主动调用 streaming.FinishStream(stream, err) 记录 RPCFinish 事件 示例代码:[kitex-examples:thrift_streaming/client/demo_client.go#L119](https://github.com/cloudwego/kitex-examples/blob/v0.3.1/thrift_streaming/client/demo_client.go#L119) @@ -186,6 +199,7 @@ stream, err := streamClient.Echo(ctx, streamcall.WithHostPorts("127.0.0.1:8888") ###### Stream Client 注意:「Recv 返回 `io.EOF` 或其他 non-nil error」表示 server 已发送结束(或出错) + 1. 此时 Kitex 才会记录 RPCFinish 事件(Tracer 依赖该事件) 2. 如 client 和 server 约定了其他结束方式,应主动调用 streaming.FinishStream(stream, err) 记录 RPCFinish 事件 @@ -203,15 +217,14 @@ stream, err := streamClient.Echo(ctx, streamcall.WithHostPorts("127.0.0.1:8888") 示例代码:[kitex-examples:thrift_streaming/client/demo_client.go#L162](https://github.com/cloudwego/kitex-examples/blob/v0.3.1/thrift_streaming/client/demo_client.go#L162) - #### Options ##### StreamClient Options Kitex 在设计上区分了 Client(for KitexThrift PingPong API)和 StreamClient(for Streaming API),并且要求 StreamClient 使用另一套 Option(类型不同),避免用户给 StreamClient 指定了不支持的 Option。 - 注意: + - 如果某个 client/callopt Option 没有对应的 streamclient/streamcall Option(例如 WithRPCTimeout),说明 StreamClient 不支持该能力 - 如果你认为 StreamClient 应当支持该能力,可以[给 Kitex 提 issue](https://github.com/cloudwego/kitex/issues) @@ -223,6 +236,7 @@ Kitex 在设计上区分了 Client(for KitexThrift PingPong API)和 StreamCl - `WithSendMiddleware`、`WithSendMiddlewareBuilder`:详见 Recv/Send 中间件 示例代码: + ```go import "github.com/cloudwego/kitex/client/streamclient" @@ -233,10 +247,12 @@ var streamClient = testservice.MustNewStreamClient( ``` ###### streamcall.Option + - 在创建 Stream 时指定 - 优先级高于同名(如果有的话)的 streamclient.Option 示例代码: + ```go import "github.com/cloudwego/kitex/client/callopt/streamcall" @@ -265,7 +281,6 @@ stream, err := streamClient.Echo( - 该 Option 主要是允许 gRPC/Protobuf Streaming 的 Unary API 使用与 PingPong API 相同的 Server Middleware(统一了入参) - 对于 Thrift Streaming,用户无需关注(不推荐使用 Unary API,且 Kitex 已默认指定该 Option) - ### 服务治理 | Governance #### 超时 | Timeout @@ -273,15 +288,19 @@ stream, err := streamClient.Echo( ##### 连接超时 支持通过 option 指定: -- streamclient.WithConnectTimeout + +- streamclient.WithConnectTimeout - streamcall.WithConnectTimeout (优先级高于前者) ##### 请求超时(不支持) + 没有对应的 Option。 对于 Streaming API,[Kitex 的 Timeout 中间件会直接调用 next](https://github.com/cloudwego/kitex/blob/v0.9.1/client/rpctimeout.go#L101)。 ##### Stream 超时 + 可通过 `context.WithTimeout` 或 `context.WithDeadline` 创建带有 Deadline 的 context,并在创建 Stream 时指定该 context,用于控制 Stream 的整体执行时间: + - Kitex Client - 通过 header `grpc-timeout` 发送给服务端 - 超时后 Recv/Send 会直接返回 `rpc error: code = 4 desc = context deadline exceeded` @@ -290,6 +309,7 @@ stream, err := streamClient.Echo( - 超时后 Recv/Send 会直接返回 `rpc error: code = 4 desc = context deadline exceeded` 示例代码: + ```go // inject deadline into context BEFORE creating a stream ctx, cancel := context.WithTimeout(context.Background(), time.Second) @@ -299,19 +319,22 @@ stream, err := cli.Echo(ctx) ``` ##### Recv/Send 超时 + 可使用 Kitex 提供的 `streaming.CallWithTimeout` 方法。 ###### Client 注意: + 1. 需要 **在创建 Stream 之前** 给 ctx 注入 cancel(用 WithCancel 或 WithTimeout 都可以,取决于需求) 2. 将 cancel 方法作为 `streaming.CallWithTimeout` 的第二个参数 - - 1. 否则 Send/Recv 可能会长时间阻塞等待(取决于 server 端),导致 goroutine 泄漏 + + 1. 否则 Send/Recv 可能会长时间阻塞等待(取决于 server 端),导致 goroutine 泄漏 3. Client 端的 `stream.Close()` 的语义是 `CloseSend`,告诉 server 不再会有新消息(server recv 返回 `io.EOF`),并不会结束接收消息,因此不能用于 cancel 方法。 示例代码: + ```go import "github.com/cloudwego/kitex/pkg/streaming" @@ -356,29 +379,35 @@ err = streaming.CallWithTimeout(time.Second, cancel, func() (errRecv error) { ``` #### 熔断 | CircuitBreak + 只支持 **创建连接(Stream)时** 的错误率熔断。 不支持 Recv/Send 的熔断。 - #### 重试 | Retry (不支持) + 不支持重试。 #### Fallback (不支持) + Streaming API 不支持 fallback。 #### 负载均衡 | LoadBalancer + - 仅支持创建 Stream 时(等同于创建网络连接)的负载均衡 - 如已经创建 Stream,后续的 Send/Recv 只会发往该 Stream 的对端 - 业务需自行处理流量倾斜问题,避免造成负载不均 ##### 一致性哈希 + 注意:由于在中间件中获取的 Request 总是 nil,因此 keyFunc 不能直接读取 request 参考方案: + 1. 在创建 Stream 前,先计算好 hashKey,放入 ctx 中 2. 在 keyFunc 里从 ctx 读取并返回 示例代码: + ```go streamClient := testservice.MustNewStreamClient( "demo-server", @@ -402,7 +431,8 @@ ctx := context.WithKey(context.background(), "MY_HASH_KEY", keyFunc(request)) stream, err := streamClient.Echo(ctx, request) ``` -#### Server 端限流 | Limit (QPS/Concurrency) +#### Server 端限流 | Limit (QPS/Concurrency) + - 支持在创建 Stream 时限流 - 创建 Stream 后对 Recv/Send 的调用无限制,需要业务自行实现 @@ -413,10 +443,11 @@ stream, err := streamClient.Echo(ctx, request) ##### Client Middleware 说明: + - Client 中间件的执行**仅覆盖「创建 Stream」的环节**(详见后附示意图) - Stream 创建完成、返回业务代码后,中间件就执行完成了 - request 总是 nil(包括 Server Streaming API) -- response 总是 *[streaming.Result](https://github.com/cloudwego/kitex/blob/v0.8.0/pkg/streaming/streaming.go#L67) 类型,该类型包含的 Stream 最终会返回给业务代码 +- response 总是 \*[streaming.Result](https://github.com/cloudwego/kitex/blob/v0.8.0/pkg/streaming/streaming.go#L67) 类型,该类型包含的 Stream 最终会返回给业务代码 - 如有需要,可替换该 Stream,加入自定义逻辑(基于 [decorator 模式](https://zh.wikipedia.org/wiki/%E4%BF%AE%E9%A5%B0%E6%A8%A1%E5%BC%8F)) - 如获取到的 err != nil,说明创建 Stream 失败 - **Client 中间件无法获取到 Recv、Send 的 Message** @@ -424,6 +455,7 @@ stream, err := streamClient.Echo(ctx, request) ###### 执行流示意图: 注意: + - 下图为 Bidirectional API 流程(Client Streaming API 也类似) - 但 Server Streaming API 略有不同,[在生成代码(kitex_gen)里调用了 Send 及 Close](https://github.com/cloudwego/kitex-examples/blob/v0.3.1/thrift_streaming/kitex_gen/echo/testservice/testservice.go#L336),然后才返回业务代码 @@ -431,13 +463,14 @@ stream, err := streamClient.Echo(ctx, request) ###### 获取到的 Request/Response 字段类型 -| | request | response | -|:----------------:|:-----------------:|:-----------------:| -| Bidirectional | interface{} = nil | *streaming.Result | -| Client Streaming | interface{} = nil | *streaming.Result | -| Server Streaming | interface{} = nil | *streaming.Result | +| | request | response | +| :--------------: | :---------------: | :----------------: | +| Bidirectional | interface{} = nil | \*streaming.Result | +| Client Streaming | interface{} = nil | \*streaming.Result | +| Server Streaming | interface{} = nil | \*streaming.Result | 注: + 1. Server Streaming API 请求也无法在中间件中读取 request,请使用 Client Send Middleware 获取 2. Thrift Streaming Unary API 的参数类型和 PingPong API 一致 @@ -462,8 +495,9 @@ func clientMW(next endpoint.Endpoint) endpoint.Endpoint { ##### Server Middleware 说明: + - Server 中间件的 next 方法里涵盖了整个 server handler 的处理过程 -- request 总是 *[streaming.Args](https://github.com/cloudwego/kitex/blob/v0.9.1/pkg/streaming/streaming.go#L70) 类型,该类型包含的 Stream 最终会返回给业务代码 +- request 总是 \*[streaming.Args](https://github.com/cloudwego/kitex/blob/v0.9.1/pkg/streaming/streaming.go#L70) 类型,该类型包含的 Stream 最终会返回给业务代码 - 如有需要,可替换该 Stream,加入自定义逻辑(基于 [decorator 模式](https://zh.wikipedia.org/wiki/%E4%BF%AE%E9%A5%B0%E6%A8%A1%E5%BC%8F)) - response 总是 nil(包括 Client Streaming API) - 如获取到的 err != nil,说明内层 Server 中间件或 handler 返回了 error @@ -485,13 +519,14 @@ func clientMW(next endpoint.Endpoint) endpoint.Endpoint { ###### 获取到的 Request/Response 字段类型 -| | request | response | -|:----------------:|:---------------:|:-----------------:| -| Bidirectional | *streaming.Args | interface{} = nil | -| Client Streaming | *streaming.Args | interface{} = nil | -| Server Streaming | *streaming.Args | interface{} = nil | +| | request | response | +| :--------------: | :--------------: | :---------------: | +| Bidirectional | \*streaming.Args | interface{} = nil | +| Client Streaming | \*streaming.Args | interface{} = nil | +| Server Streaming | \*streaming.Args | interface{} = nil | 注意: + 1. Server Streaming API 请求也无法在中间件中读取 client request,请使用 Server Recv Middleware 获取 2. Thrift Streaming Unary API 的参数类型和 PingPong API 一致 @@ -512,6 +547,7 @@ func serverMW(next endpoint.Endpoint) endpoint.Endpoint { } } ``` + #### Recv/Send 中间件 Recv/Send 中间件提供了一种简便的方式,可以在消息的收发之上应用 decorator 模式,增加自定义逻辑。 @@ -522,7 +558,7 @@ Recv/Send 中间件提供了一种简便的方式,可以在消息的收发之 注意:在 Recv Middleware 中,需要**先调用 next,才能读到 message**。 -###### StreamClient +###### StreamClient 注意:Client Recv 的是 API 的 response 类型。 @@ -547,6 +583,7 @@ var streamClient = testservice.MustNewStreamClient( }), ) ``` + ###### Server 注意:Server Recv 的是 API 的 request 类型。 @@ -563,6 +600,7 @@ svr := test.NewServer(new(TestServiceImpl), }), ) ``` + ##### Send Middleware ###### StreamClient @@ -590,6 +628,7 @@ var streamClient = testservice.MustNewStreamClient( }), ) ``` + ###### Server 注意:Server Send 的是 API 的 response 类型。 @@ -612,6 +651,7 @@ svr := test.NewServer(new(TestServiceImpl), 我们可以通过给用于创建 Stream 的 ctx 注入 key,实现在 middleware 之间共享数据的能力。 Kitex 提供了一组简单的工具方法,通过给 ctx 注入一个 sync.Map ,以便在各 middleware 之间交换数据: + - [contextmap.WithContextMap(ctx)](https://github.com/cloudwego/kitex/blob/v0.9.1/pkg/utils/contextmap/contextmap.go#L32C6-L32C20) - [contextmap.GetContextMap(ctx)](https://github.com/cloudwego/kitex/blob/v0.9.1/pkg/utils/contextmap/contextmap.go#L37) @@ -654,6 +694,7 @@ streamClient = testservice.MustNewStreamClient( ##### Server 示例代码 Server 端与 Client 端不同,进入 Middleware 时已经创建好了 Stream,因此不能在 Server Middleware 里注入,但可以通过如下方式实现: + - 用 `server.WithMetaHandler` Option 指定一个 `MetaHandler` - 该 `MetaHandler` 需要实现 `StreamingMetaHandler` 接口 - 在该 handler 的 `OnReadStream` 里给 ctx 注入 `sync.Map`,返回新的 ctx @@ -667,7 +708,9 @@ server.WithMetaHandler(remote.NewCustomMetaHandler(remote.WithOnReadStream( }, ))) ``` + 注: + 1. 完整示例代码可参考:[kitex-tests: TestCustomMetaHandler](https://github.com/cloudwego/kitex-tests/blob/main/thrift_streaming/thrift_test.go#L1090) 2. 如果暂时不想升级到 rc 版,可参考 [customMetaHandler](https://github.com/cloudwego/kitex/blob/v0.9.1-rc1/pkg/remote/custom_meta_handler.go#L29) 实现一个 MetaHandler @@ -676,6 +719,7 @@ server.WithMetaHandler(remote.NewCustomMetaHandler(remote.WithOnReadStream( 请参考:[CloudWeGo 官网 - Kitex - Metainfo](/zh/docs/kitex/tutorials/advanced-feature/metainfo/#kitex-grpc-metadata) 的「gRPC Metadata」一节。 注意: + - metainfo - Key 里不能包含小写字母和横线,例如 "Abc", "A-B" 都是无效 key,会被丢弃 - metadata @@ -683,7 +727,6 @@ server.WithMetaHandler(remote.NewCustomMetaHandler(remote.WithOnReadStream( - header & trailer - Key 不能包含大写字母,否则会导致客户端报错 - ### 可观测性 | Observability #### 基本埋点:RPCStart 和 RPCFinish @@ -698,12 +741,12 @@ Kitex 用户可以通过添加自己的 Tracer,在 Finish() 方法里处理该 如果自定义 Tracer 实现了 [rpcinfo.StreamEventReporter](https://github.com/cloudwego/kitex/blob/v0.9.1/pkg/rpcinfo/tracer.go#L31) 接口,Kitex 会注入 Recv、Send 中间件,在每次 Recv、Send 执行完后调用 tracer 的 ReportStreamEvent 方法; 在该方法里,可以获取到本次 Recv、Send 的消息大小:(注意不要另起 goroutine,否则可能读取到的不是本次调用) + - ri.Stats().LastSendSize() - ri.Stats().LastRecvSize() 具体示例可参考:[kitex-tests: testTracer](https://github.com/cloudwego/kitex-tests/blob/96b97d00bc099eba8bea181decb4d4f9e77df1cb/thrift_streaming/thrift_tracing_test.go#L77) - ### 泛化调用 | Generic (暂未支持) > 计划实现,但暂无明确时间表。 @@ -714,12 +757,13 @@ Kitex 用户可以通过添加自己的 Tracer,在 Finish() 方法里处理该 gRPC/HTTP2 的实现基于「本地缓冲区」,Send 和 Recv 操作是直接在缓冲区上操作的。 因此需注意以下几点: + 1. 「Send 返回 nil」只表明消息放入了本地缓冲区,**不等于**「消息已发送到对端」 2. Send 和 Recv 操作的「耗时」和 PingPong API 的「Latency」含义有显著差别: - - 1. 如果对端的 Recv 调用频率更高,那么本地的 Send 通常会立即返回(缓冲区总是有空闲) - 2. 如果对端的 Recv 调用频率更低,那么本地的 Send 可能会阻塞较长时间(等待对方消费腾出缓冲区) - 3. 如果缓冲区里有数据,Recv 调用会立刻返回,否则需要等待对端的 Send + + 1. 如果对端的 Recv 调用频率更高,那么本地的 Send 通常会立即返回(缓冲区总是有空闲) + 2. 如果对端的 Recv 调用频率更低,那么本地的 Send 可能会阻塞较长时间(等待对方消费腾出缓冲区) + 3. 如果缓冲区里有数据,Recv 调用会立刻返回,否则需要等待对端的 Send #### Client/Server 中间件无法读到 Request/Response @@ -727,7 +771,6 @@ gRPC/HTTP2 的实现基于「本地缓冲区」,Send 和 Recv 操作是直接 对于 Client Streaming/Server Streaming,虽然形式上和 PingPong API 类似(有 Request/Response),但是底层实现完全不同,在中间件中是读不到的。 请使用 Recv/Send 中间件处理流上的消息。 - #### 采集 RPCFinish:client 请求 Server/Bidirectional API 需调用 Recv 收到 non-nil error - 对于 Server/Bidirectional Streaming API,Kitex Client 将 Recv() 收到 non-nil error(`io.EOF` 或其他错误)作为流结束的标志,此时才会记录 RPCFinish 事件 @@ -782,6 +825,7 @@ if someCondition { ``` 补充说明: + - Server Streaming API,client 在发起请求、收到 stream 对象前,就已经关闭了 send stream([在生成代码里调用的 close](https://github.com/cloudwego/kitex-examples/blob/v0.3.1/thrift_streaming/kitex_gen/echo/testservice/testservice.go#L336)),因此 client 不能再发送新的消息告知 server,只能用 cancel 的方式提前关闭链接,这样才能让 server 端感知到 - 由于没有用 `st.Recv()` 收到 non-nil error,因此需要手动调用 `streaming.FinishStream(st, err)` 来产生该 stream 对应的 `RPCFinish` 事件 -- 对于 Bidirectional Streaming,这种方式也适用,但最好手动调用 `st.Close()` 或向 server 发送先前约定好的消息。无论哪种情况,都不要忘记调用 `streaming.FinishStream` \ No newline at end of file +- 对于 Bidirectional Streaming,这种方式也适用,但最好手动调用 `st.Close()` 或向 server 发送先前约定好的消息。无论哪种情况,都不要忘记调用 `streaming.FinishStream` diff --git a/content/zh/docs/kitex/Tutorials/basic-feature/visit_directly.md b/content/zh/docs/kitex/Tutorials/basic-feature/visit_directly.md index d7c2b2ae6f..6c821a8c7b 100644 --- a/content/zh/docs/kitex/Tutorials/basic-feature/visit_directly.md +++ b/content/zh/docs/kitex/Tutorials/basic-feature/visit_directly.md @@ -23,8 +23,6 @@ if err != nil { ``` - - ## 指定 URL 进行调用 在进行调用时,可以通过 `callopt.WithURL` 指定,通过该 option 指定的 URL,会经过默认的 DNS resolver 解析后拿到 host 和 port,此时其等效于 `callopt.WithHostPort`。 @@ -39,8 +37,6 @@ if err != nil { } ``` - - ## 自定义 DNS resolver 此外也可以自定义 DNS resolver @@ -55,12 +51,8 @@ type Resolver interface { 参数为 URL,返回值为访问的 server 的 "host:port"。 - - 通过 `client.WithHTTPResolver` 指定用于 DNS 解析的 resolver。 - - ```go import "github.com/cloudwego/kitex/client/callopt" ... diff --git a/content/zh/docs/kitex/Tutorials/basic-feature/warming_up.md b/content/zh/docs/kitex/Tutorials/basic-feature/warming_up.md index 5f15bced28..739ee4fb83 100644 --- a/content/zh/docs/kitex/Tutorials/basic-feature/warming_up.md +++ b/content/zh/docs/kitex/Tutorials/basic-feature/warming_up.md @@ -59,7 +59,6 @@ type PoolOption struct { #### 创建 client 的时候执行服务发现 - ```go cli, err := myservice.NewClient(psm, client.WithWarmingUp(&warmup.ClientOption{ ResolverOption: &warmup.ResolverOption{ diff --git a/content/zh/docs/kitex/Tutorials/code-gen/_index.md b/content/zh/docs/kitex/Tutorials/code-gen/_index.md index f9bc170f26..7e11f67cf3 100644 --- a/content/zh/docs/kitex/Tutorials/code-gen/_index.md +++ b/content/zh/docs/kitex/Tutorials/code-gen/_index.md @@ -4,5 +4,4 @@ linkTitle: "代码生成" weight: 5 date: 2021-08-26 description: > - --- diff --git a/content/zh/docs/kitex/Tutorials/code-gen/code_generation.md b/content/zh/docs/kitex/Tutorials/code-gen/code_generation.md index ddf99d1e33..1d6f818c0c 100644 --- a/content/zh/docs/kitex/Tutorials/code-gen/code_generation.md +++ b/content/zh/docs/kitex/Tutorials/code-gen/code_generation.md @@ -5,12 +5,10 @@ weight: 1 description: > --- -> 本篇文档及示例所使用的 Kitex 代码生成工具版本为 v0.5.0 +> 本篇文档及示例所使用的 Kitex 代码生成工具版本为 v0.5.0 **kitex** 是 Kitex 框架提供的用于生成代码的一个命令行工具。目前,kitex 支持 thrift 和 protobuf 的 IDL,并支持生成一个服务端项目的骨架。 - - ## 安装 > Windows 环境,需要 Kitex 命令行工具版本 >= v0.5.2 @@ -25,7 +23,7 @@ go install github.com/cloudwego/kitex/tool/cmd/kitex@latest 你也可以自己下载 Kitex 源码后,进入 `tool/cmd/kitex` 目录执行 `go install` 进行安装 -完成后,可以通过执行 `kitex -version` 查看工具版本,或者 `kitex -help` 查看使用帮助。 +完成后,可以通过执行 `kitex -version` 查看工具版本,或者 `kitex -help` 查看使用帮助。 ## 生成代码 @@ -91,7 +89,7 @@ kitex_gen/ 上文的案例代码并不能直接运行,需要自己完成 NewClient 和 NewServer 的构建。kitex 命令行工具提供了 `-service` 参数能直接生成带有脚手架的代码,执行如下命令: ```shell -kitex -service mydemoservice demo.thrift +kitex -service mydemoservice demo.thrift ``` 生成结果如下: @@ -104,13 +102,12 @@ kitex -service mydemoservice demo.thrift └── script // 构建服务相关脚本 │  └── bootstrap.sh ├── kitex_gen -    └── .... +    └── ....    ``` 在 `handler.go` 的接口中填充业务代码后,执行 `main.go` 的主函数即可快速启动 Kitex Server。 - ## 库依赖 kitex 生成的代码会依赖相应的 Go 语言代码库: @@ -144,13 +141,12 @@ option go_package = "hello.world"; // or hello/world 如果你给 `go_package` 赋值一个完整的导入路径(import path),那么该路径必须匹配到当前模块的 kitex_gen 才会生成代码。即: -* `go_package="${当前模块的 import path}/kitex_gen/hello/world";`:OK,kitex 会为该 IDL 生成代码; -* `go_package="${当前模块的 import path}/hello/world";`:kitex 不会为该 IDL 生成代码; -* `go_package="any.other.domain/some/module/kitex_gen/hello/world";`:kitex 不会为该 IDL 生成代码; +- `go_package="${当前模块的 import path}/kitex_gen/hello/world";`:OK,kitex 会为该 IDL 生成代码; +- `go_package="${当前模块的 import path}/hello/world";`:kitex 不会为该 IDL 生成代码; +- `go_package="any.other.domain/some/module/kitex_gen/hello/world";`:kitex 不会为该 IDL 生成代码; 你可以通过命令行参数 `--protobuf Msome.proto=your.package.name/kitex_gen/wherever/you/like` 来覆盖某个 proto 文件的 `go_package` 值。具体用法说明可以参考 Protocol Buffers 的[官方文档](https://developers.google.com/protocol-buffers/docs/reference/go-generated#package)。 - ## 选项 本文描述的选项可能会过时,可以用 `kitex -h` 或 `kitex --help` 来查看 kitex 的所有可用的选项。 @@ -167,9 +163,9 @@ option go_package = "hello.world"; // or hello/world 2. 如果当前目录不在 `$GOPATH/src` 下,那么必须指定该参数。 3. 如果指定了 `-module` 参数,那么 kitex 会从当前目录开始往上层搜索 go.mod 文件 - - 如果不存在 go.mod 文件,那么 kitex 会调用 `go mod init` 生成 go.mod; - - 如果存在 go.mod 文件,那么 kitex 会检查 `-module` 的参数和 go.mod 里的模块名字是否一致,如果不一致则会报错退出; - - 最后,go.mod 的位置及其模块名字会决定生成代码里的 import path。 + - 如果不存在 go.mod 文件,那么 kitex 会调用 `go mod init` 生成 go.mod; + - 如果存在 go.mod 文件,那么 kitex 会检查 `-module` 的参数和 go.mod 里的模块名字是否一致,如果不一致则会报错退出; + - 最后,go.mod 的位置及其模块名字会决定生成代码里的 import path。 #### `-I path` @@ -178,19 +174,18 @@ option go_package = "hello.world"; // or hello/world path 输入也可以支持 git 拉取,当前缀为 git@,http://,https:// 时,会拉取远程 git 仓库到本地,并将其列入搜索路径。使用方式如下: ```shell -kitex -module xx -I xxx.git abc/xxx.thrift +kitex -module xx -I xxx.git abc/xxx.thrift ``` 或使用 `@xxx` 指定分支拉取: ```shell -kitex -module xx -I xxx.git@branch abc/xxx.thrift +kitex -module xx -I xxx.git@branch abc/xxx.thrift ``` 执行时会先拉取 git 仓库,存放于 ~/.kitex/cache/xxx/xxx/xxx@branch 目录下,然后再在此目录下搜索 abc/xxx.thrift 并生成代码 - #### `-v` 或 `-verbose` 输出更多日志。 @@ -205,7 +200,6 @@ kitex -module xx -I xxx.git@branch abc/xxx.thrift 该选项会生成一个合并了目标 IDL 文件中所有 service 方法的 `CombineService`,并将其用作 main 包里使用的 service 定义。注意这个模式下,被合并的 service 之间不能有冲突的方法名。 - #### `-protobuf value` 传递给 protoc 的参数。会拼接在 `-go_out` 的参数后面。可用的值参考 `protoc` 的帮助文档。 @@ -214,7 +208,6 @@ kitex -module xx -I xxx.git@branch abc/xxx.thrift 传递给 thriftgo 的参数。会拼接在 `-g go:` 的参数后面。可用的值参考 `thriftgo` 的帮助文档。kitex 默认传递了 `naming_style=golint,ignore_initialisms,gen_setter,gen_deep_equal`,可以被覆盖。 - #### `-record` 有的场景下,可能需要多次运行 Kitex 命令,为多个 IDL 生成代码。 `-record` 参数用于自动记录每次执行的 Kitex 命令并生成脚本文件,以便更新时批量重新执行。 @@ -251,7 +244,6 @@ kitex -module xxx xxxd.thrift 想重新生成代码,执行 kitex-all.sh 即可。若想手动调整,打开脚本文件直接编辑命令即可 - #### `-gen-path` > 目前只在 thrift 场景生效,protobuf 侧待后续完善实现。 @@ -274,20 +266,19 @@ kitex -protobuf-plugin {plugin_name:options:out_dir} idl/myservice.proto - options: 表示传递给插件的选项;通常会传递一些类似 "go module" 等信息 - out_dir: 表示插件生成代码的路径;如无特殊需求,一般指定为 "." 即可 -以上 3 个选项可映射为如下的 protoc 命令,可被 kitex 自动拼接&执行: +以上 3 个选项可映射为如下的 protoc 命令,可被 kitex 自动拼接&执行: ```shell protoc --{$plugin_name}_out={$out_dir} - --{$plugin_name}_opt={$options} + --{$plugin_name}_opt={$options} idl/myservice.proto -``` +``` 例如希望使用 [protoc-gen-validator](https://github.com/cloudwego/protoc-gen-validator) 插件,可以执行如下命令: ```shell -kitex +kitex -protobuf-plugin=validator:module=toutiao/middleware/kitex,recurse=true:. idl/myservice.proto ``` - diff --git a/content/zh/docs/kitex/Tutorials/code-gen/custom_tpl.md b/content/zh/docs/kitex/Tutorials/code-gen/custom_tpl.md index cd00f58756..7b580292f3 100644 --- a/content/zh/docs/kitex/Tutorials/code-gen/custom_tpl.md +++ b/content/zh/docs/kitex/Tutorials/code-gen/custom_tpl.md @@ -17,6 +17,7 @@ Kitex 支持了自定义模板功能,如果默认的模板不能够满足大 1. Kitex 代码生成分成两部分,kitex_gen 和 mainPkg(剩下的 main.go、handler.go )等等,kitex_gen 无论采用何种生成都不会改变;mainPkg 和 custom layout 只能二选一,如果制定了 custom layout 就不会再生成 mainPkg。 ## 使用场景 + 当默认的脚手架模板不能够满足用户的需求,比如想要生成 MVC Layout、统一进行错误处理等。 ## 使用方式 @@ -47,7 +48,6 @@ body: ... # 模板内容 https://github.com/cloudwego/cwgo/tree/main/tpl/kitex - ## 附录 ### PackageInfo 结构体常用内容 @@ -62,7 +62,7 @@ type PackageInfo struct { NoFastAPI bool Version string RealServiceName string - Imports map[string]map[string]bool + Imports map[string]map[string]bool ExternalKitexGen string Features []feature FrugalPretouch bool @@ -106,8 +106,8 @@ type MethodInfo struct { // Parameter . type Parameter struct { - Deps []PkgInfo - Name string + Deps []PkgInfo + Name string RawName string // StructB Type string // *PkgA.StructB } diff --git a/content/zh/docs/kitex/Tutorials/code-gen/idl_trimmer.md b/content/zh/docs/kitex/Tutorials/code-gen/idl_trimmer.md index 51c0bc6903..f56ee96f61 100644 --- a/content/zh/docs/kitex/Tutorials/code-gen/idl_trimmer.md +++ b/content/zh/docs/kitex/Tutorials/code-gen/idl_trimmer.md @@ -7,38 +7,45 @@ description: "使用IDL裁切工具裁切不必要的IDL定义" --- ## 简介 + [Thriftgo](https://github.com/cloudwego/thriftgo) 是 Go 语言实现的 Thrift IDL 解析和代码生成器,支持完善的 Thrift IDL 语法和语义检查。相较 Apache Thrift 官方的 Golang 生成代码,Thriftgo 做了一些问题修复且支持插件机制,用户可根据需求自定义生成代码。Kitex 的代码生成工具就是 Thriftgo 的插件实现之一。 -一些 IDL 仓库可能会因为没有及时维护清理废弃的内容,随着版本迭代,无关内容越来越多,造成了生成的 Golang 代码仓库变得很大,IDL 的可读性也下降。也可能由于引用或者间接引用了过多的IDL,导致很多无关的结构被纳入生成代码中,导致生成代码体积过大或生成过程产生异常。这些问题在复杂项目实践中出现较为频繁,可能阻塞业务的开发流程。 +一些 IDL 仓库可能会因为没有及时维护清理废弃的内容,随着版本迭代,无关内容越来越多,造成了生成的 Golang 代码仓库变得很大,IDL 的可读性也下降。也可能由于引用或者间接引用了过多的IDL,导致很多无关的结构被纳入生成代码中,导致生成代码体积过大或生成过程产生异常。这些问题在复杂项目实践中出现较为频繁,可能阻塞业务的开发流程。 -Thriftgo 在 v0.3.1+ 版本提供了 Thrift IDL 裁切功能,用于针对不会被 service 引用到的结构进行裁剪,以删除对 RPC 无影响和依赖的结构,从而减少没有用的生成代码。 +Thriftgo 在 v0.3.1+ 版本提供了 Thrift IDL 裁切功能,用于针对不会被 service 引用到的结构进行裁剪,以删除对 RPC 无影响和依赖的结构,从而减少没有用的生成代码。 -该功能可以直接通过 Thriftgo 项目下提供的 Trimmer 工具单独使用,生成裁切过后的 IDL,也可以配合 Thriftgo/Kitex 命令行使用,在代码生成时直接过滤掉无用的内容。 +该功能可以直接通过 Thriftgo 项目下提供的 Trimmer 工具单独使用,生成裁切过后的 IDL,也可以配合 Thriftgo/Kitex 命令行使用,在代码生成时直接过滤掉无用的内容。 ## 裁切原理 + - 遍历给定 IDL 文件中包含的所有 service,找到 service 和 method 里所有直接或者间接引用的 struct 结构体,将他们标记为“有用” - 扫描该项目直接或间接引用的所有 IDL,对于所有的 struct 结构体,如果没有被标记为“有用”,就裁切掉 - 由于业务开发往往通过 IDL 来引入枚举和常数,所以工具不对 IDL 中的typedef、枚举和常数进行裁切 -- 将裁切后的结果重新输出为 .thrift 结尾的 IDL 文件,或者生成 Golang 代码 +- 将裁切后的结果重新输出为 .thrift 结尾的 IDL 文件,或者生成 Golang 代码 下面是一个示意图,裁切前,这组 IDL 文件以及内容如下: -![img](/img/docs/idl_trimmer_process1.jpg) +![img](/img/docs/idl_trimmer_process1.jpg) 使用裁切工具后,会根据 IDL A 里的 service A 遍历所有结构体,将用不到的 struct 结构体删除,最终输出如下: ![img](/img/docs/idl_trimmer_process2.jpg) - ## 使用 Trimmer 工具 + Trimmer 工具支持处理 thrift IDL 文件,并将裁切后的结果重新以 thrift IDL 文件的形式输出 -安装 Trimmer 工具: +安装 Trimmer 工具: + ```bash go install github.com/cloudwego/thriftgo/tool/trimmer@latest ``` + 查看版本/验证工具安装: + ```bash trimmer -version ``` + 使用格式: + ```bash trimmer [options] file @@ -49,25 +56,35 @@ Options: -r, --recurse [dir] 指定一个根目录,复制其目录结构到输出目录并递归地输出指定IDL及其引用IDL到相应位置。如指定-o,必须为一个目录 -m, --method [service.method] 指定只保留某个或多个 Method 进行裁切 ``` + ### 单文件处理 + 当想对单个 IDL 文件进行裁切时,可执行如下命令: + ```bash trimmer sample.thrift ``` + 执行成功后,会输出裁切后的 IDL 文件位置,你会看到如下提示: `success, dump to example_trimmed.thrift` -默认的命名为原名 + trimmed 后缀,如果想把裁切的 IDL 输出到指定目录或者重命名,可带上 -o 参数: +默认的命名为原名 + trimmed 后缀,如果想把裁切的 IDL 输出到指定目录或者重命名,可带上 -o 参数: + ```bash trimmer -o abc/my_sample.thrift sample.thrift ``` + ### 递归裁切 -如果想对某个 IDL 进行裁切的同时裁剪和输出其引用到的相关 IDL,可以使用 -r 参数: + +如果想对某个 IDL 进行裁切的同时裁剪和输出其引用到的相关 IDL,可以使用 -r 参数: + ```bash trimmer -r test_cases/ test_cases/my_idl/a.thrift ``` + 注意,当使用 -r 时,需要在 -r 参数后面指定 IDL 文件目录,工具会在这个文件夹内寻找依赖的 IDL 并裁切后维持目录结构输出(裁切依据是指定 IDL 的依赖性),默认的输出位置是 `trimmed_idl` 文件夹下。可以通过 -o 来设置输出的文件夹名称。 -输出后的目录结构如下: +输出后的目录结构如下: + ``` . ├── test_cases // 原 IDL 文件目录 @@ -80,76 +97,98 @@ trimmer -r test_cases/ test_cases/my_idl/a.thrift │ └── a.thrift └── c.thrift ``` + 注意,由于 IDL 定义本身不记录缩进、换行、顺序等,输出的新 IDL 文件的字段顺序可能与原版本不同。 ### 指定 Method 裁切 -在「裁切原理」部分提到,默认情况下,Trimmer 工具是查找所有 Service 的所有 Method 来裁切结构体。如果想将裁切逻辑精确到某个或多个 Method,可以使用 -m 参数,以 ``[service_name.method_name]`` 的方式指定 + +在「裁切原理」部分提到,默认情况下,Trimmer 工具是查找所有 Service 的所有 Method 来裁切结构体。如果想将裁切逻辑精确到某个或多个 Method,可以使用 -m 参数,以 `[service_name.method_name]` 的方式指定 + ```bash -trimmer -m MyService.MethodA -m MyService.MethodB example.thrift` +trimmer -m MyService.MethodA -m MyService.MethodB example.thrift` ``` -当目标 IDL 只有一个 Service 时,可以忽略 Service 名: + +当目标 IDL 只有一个 Service 时,可以忽略 Service 名: + ```bash trimmer -m MethodA -m MethodB example.thrift ``` -执行后,其他的 Service 以及 Method 将会被裁切掉,只有当前指定的 Method 以及其依赖的结构体会被保留。 -在 Thriftgo v0.3.3 版本(暂未发布,拉取最新 commit 即可)中,指定 method 裁切功能支持了正则表达式的 method 匹配方式。用户可以构造正则表达式来匹配`[serviceName].[methodName]`的方法名,精确指定一个或多个方法。例如: +执行后,其他的 Service 以及 Method 将会被裁切掉,只有当前指定的 Method 以及其依赖的结构体会被保留。 + +在 Thriftgo v0.3.3 版本(暂未发布,拉取最新 commit 即可)中,指定 method 裁切功能支持了正则表达式的 method 匹配方式。用户可以构造正则表达式来匹配`[serviceName].[methodName]`的方法名,精确指定一个或多个方法。例如: + ```bash -trimmer -m 'Employee.*\..*' test_cases/sample1.thrift +trimmer -m 'Employee.*\..*' test_cases/sample1.thrift ``` + 可以匹配 "Employee" 开头的 service 下的全部方法。(注:"." 在正则表达式有意义,最好使用 "\." 来匹配) -也可以使用一些 perl 风格的表达式进行一些高级裁切操作,例如: +也可以使用一些 perl 风格的表达式进行一些高级裁切操作,例如: + ```bash trimmer -m '^(?!EmployeeService.getEmployee).*$' test_cases/sample1.thrift ``` + 可以匹配除了 `EmployeeService.getEmployee` 外的所有方法。执行这条命令,可以单独从 IDL 中删除该方法及其依赖(且其他方法无依赖)的结构。 ### 保护结构不被裁切 + 基于特定开发需要,可能希望裁切工具保留一些结构不被裁切,从而利用对应的生成代码。可以在想要保护的 struct、union、exception 的上方使用注释 `@preserve` 进行标注,裁剪时将无条件将其保留。可以和其他注释共存,但需要确保 `@preserve` 注释位于单独的一行内。 例如: + ```thrift // @preserve struct Useless{ } ``` -即使该结构没有被引用,其仍然会在裁剪后被保留。 -本功能默认开启,可以通过设置 -p 或 -preserve 参数为 false 将其禁用。例如: +即使该结构没有被引用,其仍然会在裁剪后被保留。 + +本功能默认开启,可以通过设置 -p 或 -preserve 参数为 false 将其禁用。例如: + ```bash trimmer -p false sample.thrift ``` + 此时 Trimmer 工具将无视 @preserve 注释进行裁剪。 ## 在 Kitex Tool 中集成 + Trimmer 功能也可以直接集成在 Thriftgo/Kitex 生成代码中,但首先确保 Thriftgo 版本不低于 v0.3.1 -以 Kitex 为例,使用时添加 `-thrift trim_idl` 参数,例如: +以 Kitex 为例,使用时添加 `-thrift trim_idl` 参数,例如: + ```bash kitex -module xx -thrift trim_idl xxx.thrift` ``` + 使用该参数时,命令行会额外输出额外提示: `[WARN] You Are Using IDL Trimmer` 代码生成时,将会对所用到 IDL 进行裁切,最终生成的 Golang 代码就不会有无用的 Struct 结构体了。 ## 使用 yaml 进行配置 -为了方便通过 Kitex/Thriftgo 集成方法进行裁切时使用 trimmer tool 的参数配置,Thriftgo v0.3.3 版本(暂未发布,拉取最新 commit 即可)为 trimmer 工具提供了 yaml 配置文件支持。在集成 Kitex/Thriftgo 或直接使用 trimmer 工具时,trimmer 都会自动扫描并应用当前执行的目录(os.Getwd())下的 trim_config.yaml 配置文件。 + +为了方便通过 Kitex/Thriftgo 集成方法进行裁切时使用 trimmer tool 的参数配置,Thriftgo v0.3.3 版本(暂未发布,拉取最新 commit 即可)为 trimmer 工具提供了 yaml 配置文件支持。在集成 Kitex/Thriftgo 或直接使用 trimmer 工具时,trimmer 都会自动扫描并应用当前执行的目录(os.Getwd())下的 trim_config.yaml 配置文件。 在启用 yaml 配置文件时,你会收到类似提示: -`using trim config: /xxx/trim_config.yaml` +`using trim config: /xxx/trim_config.yaml` 除了为集成 Kitex/Thriftgo 提供一种配置参数的方法,通过书写 yaml 配置文件,IDL 作者可以向用户或代码维护者提前圈定裁切的保留内容等,IDL 使用者也可以以此作为模板方便批量裁切或传递给其他人。 ### Yaml 配置示例: + ```yaml methods: -- "TestService.func1" -- "TestService.func3" + - "TestService.func1" + - "TestService.func3" preserve: true preserved_structs: -- "usefulStruct" + - "usefulStruct" ``` -### 配置格式 + +### 配置格式 + 目前可通过 yaml 配置的选项如下: + - methods:字符串数组,和 -m 参数等效,表示使用指定 method 裁切功能。格式和功能请参考“指定 Method 裁切”部分。如果命令行参数指定了 -m 参数,会覆盖此处 yaml 配置。 - preserve:bool 型,和 -p 参数等效,置为 false 表示禁用 @preserve 注释等保护结构不被裁剪的功能,默认为 true。如果命令行参数指定了 -p 参数,会覆盖此处 yaml 配置。 - preserved_structs:字符串数组,表示需要保护的结构名。如果 preserve 或 命令行的 -p 参数设置为 true,trimmer 将无条件对指定名字的结构进行保留。可以用于 struct、union、exception 结构。 - diff --git a/content/zh/docs/kitex/Tutorials/code-gen/template_extension.md b/content/zh/docs/kitex/Tutorials/code-gen/template_extension.md index bc62eec7b8..9f8e07354d 100644 --- a/content/zh/docs/kitex/Tutorials/code-gen/template_extension.md +++ b/content/zh/docs/kitex/Tutorials/code-gen/template_extension.md @@ -34,23 +34,21 @@ extensions.yaml 文件提供的内容将会被应用到所有 service 定义对 dependencies: example.com/my/pkg: pkg extend_client: - import_paths: - - example.com/my/pkg - extend_option: - options = append(options, client.WithSuite(pkg.MyClientSuite())) - extend_file: |- - func Hello() { - println("hello world") - } + import_paths: + - example.com/my/pkg + extend_option: options = append(options, client.WithSuite(pkg.MyClientSuite())) + extend_file: |- + func Hello() { + println("hello world") + } extend_server: - import_paths: - - example.com/my/pkg - extend_option: - options = append(options, server.WithSuite(pkg.MyServerSuite())) - extend_file: |- - func Hello() { - println("hello world") - } + import_paths: + - example.com/my/pkg + extend_option: options = append(options, server.WithSuite(pkg.MyServerSuite())) + extend_file: |- + func Hello() { + println("hello world") + } ``` - **dependencies**:字段定义了在模板里可能会被使用到的包的列表,以及它们被引用的名字。 diff --git a/content/zh/docs/kitex/Tutorials/code-gen/validator.md b/content/zh/docs/kitex/Tutorials/code-gen/validator.md index 018f6bfff8..5965691191 100644 --- a/content/zh/docs/kitex/Tutorials/code-gen/validator.md +++ b/content/zh/docs/kitex/Tutorials/code-gen/validator.md @@ -5,15 +5,13 @@ weight: 3 description: > --- - - ## 概述 Validator 是用于支持结构体校验能力的 thriftgo 插件。 -在 IDL 中通过注解来描述约束,插件会根据注解给对应的 struct 生成 `IsValid() error ` 方法,生成在 xxx-validator.go 文件。 +在 IDL 中通过注解来描述约束,插件会根据注解给对应的 struct 生成 `IsValid() error ` 方法,生成在 xxx-validator.go 文件。 -注解采用 `vt.{ConstraintType} = "Value"` 这种形式描述。 +注解采用 `vt.{ConstraintType} = "Value"` 这种形式描述。 适用范围:struct/union 中的每个 field 。 @@ -50,10 +48,10 @@ $ go install github.com/cloudwego/thrift-gen-validator@latest 执行完 `go install` 之后,会将编译后的 `thrift-gen-validator` 二进制文件安装到 `$GOPATH/bin` 下。 -可以执行下面的命令,验证是否安装成功。 +可以执行下面的命令,验证是否安装成功。 ```shell -$ cd $(go env GOPATH)/bin +$ cd $(go env GOPATH)/bin $ ls go1.20.1 goimports hz thrift-gen-validator godotenv golangci-lint kitex thriftgo @@ -70,7 +68,7 @@ Usage of thrift-gen-validator: ## 使用 -以[快速开始](/zh/docs/kitex/getting-started/)里的 Kitex Hello 项目为例,进入示例仓库的 `hello` 目录,在 `hello.thrift` 中添加注解,例如我们对 `Request` 结构体的 `message` 字段进行约束,约束长度不超过8且要以 "kitex-" 前缀开头: +以[快速开始](/zh/docs/kitex/getting-started/)里的 Kitex Hello 项目为例,进入示例仓库的 `hello` 目录,在 `hello.thrift` 中添加注解,例如我们对 `Request` 结构体的 `message` 字段进行约束,约束长度不超过8且要以 "kitex-" 前缀开头: ``` struct Request { @@ -78,7 +76,7 @@ struct Request { } ``` -在生成 Kitex 代码时,加上 `--thrift-plugin validator` 参数,即可生成 validator 文件。 +在生成 Kitex 代码时,加上 `--thrift-plugin validator` 参数,即可生成 validator 文件。 ``` kitex --thrift-plugin validator -service a.b.c hello.thrift @@ -100,7 +98,7 @@ kitex --thrift-plugin validator -service a.b.c hello.thrift    └── k-hello.go ``` -其中对于 `Request` 结构体,新生成了 `IsValid()` 方法: +其中对于 `Request` 结构体,新生成了 `IsValid()` 方法: ``` func (p *Request) IsValid() error { @@ -115,7 +113,7 @@ func (p *Request) IsValid() error { } ``` -在后续的使用中,调用 `IsValid()` 方法对结构体进行校验即可: +在后续的使用中,调用 `IsValid()` 方法对结构体进行校验即可: ``` @@ -133,7 +131,7 @@ func (p *Request) IsValid() error { ## 支持的校验能力 -校验顺序以定义顺序为准, 'in' 和 'not_in' 这类可以定义多次的,以第一次出现的顺序为准。 +校验顺序以定义顺序为准, 'in' 和 'not_in' 这类可以定义多次的,以第一次出现的顺序为准。 ### 数字类型 diff --git a/content/zh/docs/kitex/Tutorials/framework-exten/_index.md b/content/zh/docs/kitex/Tutorials/framework-exten/_index.md index 80d330fe1e..9324ff7a8d 100644 --- a/content/zh/docs/kitex/Tutorials/framework-exten/_index.md +++ b/content/zh/docs/kitex/Tutorials/framework-exten/_index.md @@ -4,7 +4,6 @@ linkTitle: "框架扩展" weight: 6 date: 2021-08-26 description: > - --- ## 概述 diff --git a/content/zh/docs/kitex/Tutorials/framework-exten/middleware.md b/content/zh/docs/kitex/Tutorials/framework-exten/middleware.md index 7f3a2faca6..02465742a5 100644 --- a/content/zh/docs/kitex/Tutorials/framework-exten/middleware.md +++ b/content/zh/docs/kitex/Tutorials/framework-exten/middleware.md @@ -13,6 +13,7 @@ Kitex 的中间件定义在 `pkg/endpoint/endpoint.go` 中,其中最主要的 1. Endpoint 是一个函数,接受 ctx、req、resp ,返回 err,可参考下文「示例」代码; 2. Middleware(下称 MW )也是一个函数,接收同时返回一个 Endpoint。 + ```go type Middleware func(Endpoint) Endpoint ``` @@ -22,6 +23,7 @@ type Middleware func(Endpoint) Endpoint 中间件是串连使用的,通过调用传入的 next,可以得到后一个中间件返回的 response(如果有)和 err,据此作出相应处理后,向前一个中间件返回 err(**务必将 err 向上返回** )或者设置 response。 ### 客户端中间件 + #### 使用方法 1. `client.WithMiddleware` 在当前 client 中添加一个中间件,在 Service 熔断和超时中间件之后执行。 @@ -49,6 +51,7 @@ type Middleware func(Endpoint) Endpoint 6. `client.WithErrorHandler` 设置的中间件 以上可以详见 [client.go](https://github.com/cloudwego/kitex/blob/develop/client/client.go) + #### Context 中间件 Context 中间件本质上也是一种客户端中间件,但是区别是,其由 ctx 来控制是否注入以及注入哪些中间件。 @@ -57,6 +60,7 @@ Context 中间件的引入是为了提供一种能够全局或者动态注入 Cl 注意:Context 中间件会在 `client.WithMiddleware` 设置的中间件之前执行。 ### 服务端中间件 + #### 使用方法 1. `server.WithMiddleware` 在当前 server 中添加一个中间件。 @@ -76,10 +80,13 @@ Context 中间件的引入是为了提供一种能够全局或者动态注入 Cl 以上可以详见[server.go](https://github.com/cloudwego/kitex/blob/develop/server/server.go) ### 示例 -我们可以通过以下这个例子来看一下如何使用中间件。 + +我们可以通过以下这个例子来看一下如何使用中间件。 #### 获取 Request/Reponse + 假如我们现在需要在请求前打印出 request 内容,再请求后打印出 response 内容,可以编写如下的 MW(包含 streaming 调用的服务参见下文 gRPC 中间件): + ```go /* type Request struct { @@ -117,10 +124,12 @@ func ExampleMiddleware(next endpoint.Endpoint) endpoint.Endpoint { 以上方案仅为示例,**慎用于生产**:因为日志输出所有 req/resp 会有性能问题。无视 response 体大小,输出大量日志是一个非常消耗性能的操作,一个特别大的 response 可以是秒级的耗时。 ### 注意事项 + 1. 如果自定义 middleware 中用到了 RPCInfo,注意 RPCInfo 在 rpc 结束之后会被回收。如果在 middleware 中开启 goroutine 操作 RPCInfo 有可能会出现问题,请避免这类操作。 2. Middleware 为链式调用,若在任一 middleware 中使用 `result.SetSuccess()` 或其他方式修改了 response,上游 middleware 会接收到修改后的 response。 ### gRPC 中间件 + 众所周知,kitex 除了 thrift,还支持了 protobuf 和 gRPC 的编解码协议,其中 protobuf 是指只用 protobuf 来定义 payload 格式,并且其 service 定义里的方法只有 unary 方法的情况;一旦引入了 streaming 方法,那么 kitex 会使用 gRPC 协议来做编解码和通信。 使用 protobuf(仅 unary)的服务,其中间件的编写与上文一致,因为两者的设计是完全一样的。 @@ -128,6 +137,7 @@ func ExampleMiddleware(next endpoint.Endpoint) endpoint.Endpoint { 如果使用了 streaming 方法,那么中间件的编写则是完全不同的。因此,这里单独将 gRPC streaming 的中间件的用法说明列为一个单元。 对于 streaming 方法,由于存在 client stream、server stream、bidirectional stream 等形式,并且 message 的收发(Recv & Send)都是有业务逻辑控制的,所以中间件并不能 cover 到 message 本身。因此,假设要在 Message 收发环节实现请求/响应的日志打印,需要对 Kitex 的 `streaming.Stream` 做如下封装: + ```go type wrappedStream struct { streaming.Stream @@ -149,7 +159,9 @@ func newWrappedStream(s streaming.Stream) streaming.Stream { } ``` + 然后,在中间件内在特定调用时机插入封装后的 `streaming.Stream` 对象。 + ```go import "github.com/cloudwego/kitex/pkg/streaming" @@ -180,17 +192,20 @@ func DemoGRPCMiddleware(next endpoint.Endpoint) endpoint.Endpoint { 在 Kitex middleware 内获取的 request/response 参数类型在 gRPC 不同场景下的说明: -| 场景 | Request 类型 | Response 类型 | -|-----------------------------------|-------------------------|---------------------------| - | Kitex-gRPC Server Unary/Streaming | *streaming.Args | nil | - | Kitex-gRPC Client Unary | *xxxservice.XXXMethodArgs | *xxxservice.XXXMethodResult | - | Kitex-gRPC Client Streaming | nil | *streaming.Result | +| 场景 | Request 类型 | Response 类型 | +| --------------------------------- | -------------------------- | ---------------------------- | +| Kitex-gRPC Server Unary/Streaming | \*streaming.Args | nil | +| Kitex-gRPC Client Unary | \*xxxservice.XXXMethodArgs | \*xxxservice.XXXMethodResult | +| Kitex-gRPC Client Streaming | nil | \*streaming.Result | ## 总结 + Middleware 是一种比较低层次的扩展的实现,一般用于注入包含特定功能的简单代码。而在复杂场景下,一个 middleware 封装通常无法满足业务需求,这时候需要更完善的套件组装多个 middleware/options 来实现一个完整的中间层,用户可基于 suite 来进行开发,参考[扩展套件Suite](/zh/docs/kitex/tutorials/framework-exten/suite/) ## FAQ -### 如何在 middleware 里 recover handler 排除的 panic + +### 如何在 middleware 里 recover handler 排除的 panic + 问题: 想在 middleware 里 recover 自己业务的 handler 抛出的 panic,发现 panic 已经被框架 recover 了。 @@ -267,6 +282,7 @@ func (p *${XMethod}Result) GetSuccess() *${XResponse} { 以上生成代码可以在 kitex_gen 中看到。 所以,用户有三种方案获取到真实的 req 和 resp: + 1. 如果你能确定调用的具体是哪个方法,用的 req 的类型,可以直接通过类型断言拿到具体的 Args 类型,然后通过 GetReq 方法就能拿到真正的 req; 2. 对于 thrift 生成代码,通过断言 `GetFirstArgument` 或者 `GetResult`,获取到 `interface{}`,然后进行类型断言成真实的 req 或者 resp(注意:由于返回的 `interface{}` 包含类型,`interface{}` 判断 nil 无法拦截 req/resp 本身为空指针的情况,需判断断言后的 req/resp 是否为空指针); 3. 通过反射方法获取真实的请求/响应体,参考代码: @@ -281,5 +297,5 @@ var ExampleMW endpoint.Middleware = func(next endpoint.Endpoint) endpoint.Endpoi log.Infof(ctx, "response: %T", respV.Interface()) return err } -} +} ``` diff --git a/content/zh/docs/kitex/Tutorials/framework-exten/registry.md b/content/zh/docs/kitex/Tutorials/framework-exten/registry.md index ee6e6ea357..ea3fcdb6e9 100644 --- a/content/zh/docs/kitex/Tutorials/framework-exten/registry.md +++ b/content/zh/docs/kitex/Tutorials/framework-exten/registry.md @@ -8,6 +8,7 @@ description: > Kitex 支持自定义注册模块,使用者可自行扩展集成其他注册中心,该扩展定义在 pkg/registry 下。 ## 扩展接口和 Info 定义 + - 扩展接口 ```go @@ -19,7 +20,8 @@ type Registry interface { ``` - Info 定义 -Kitex 定义了部分注册信息,使用者也可以根据需要自行扩展注册信息到 Tags 中。 + Kitex 定义了部分注册信息,使用者也可以根据需要自行扩展注册信息到 Tags 中。 + ```go // Info is used for registry. // The fields are just suggested, which is used depends on design. @@ -41,6 +43,7 @@ type Info struct { ``` ## 集成到 Kitex + 通过 option 指定自己的注册模块和自定义的注册信息。注意注册需要服务信息,服务信息也是通过 option 指定。 - 指定服务信息 @@ -64,9 +67,10 @@ type Info struct { ```go svr := xxxservice.NewServer(handler, server.WithServerBasicInfo(ebi), server.WithRegistry(yourRegistry)) ``` + - 自定义 RegistryInfo - Kitex 默认赋值 ServiceName、Addr 和 PayloadCodec,若需要其他注册信息需要使用者自行注入。option: `WithRegistryInfo` + Kitex 默认赋值 ServiceName、Addr 和 PayloadCodec,若需要其他注册信息需要使用者自行注入。option: `WithRegistryInfo` ```go svr := xxxservice.NewServer(handler, server.WithRegistry(yourRegistry), server.WithRegistryInfo(yourRegistryInfo)) diff --git a/content/zh/docs/kitex/Tutorials/framework-exten/suite.md b/content/zh/docs/kitex/Tutorials/framework-exten/suite.md index 8a06d52cfc..a221f25948 100644 --- a/content/zh/docs/kitex/Tutorials/framework-exten/suite.md +++ b/content/zh/docs/kitex/Tutorials/framework-exten/suite.md @@ -9,6 +9,7 @@ description: > Suite(套件)是一种对于扩展的高级抽象,可以理解为是对于 Option 和 Middleware 的组合和封装。 在扩展过程中,我们需要要记得两点原则: + 1. Suite 套件只允许在初始化 Server、Client 的时候设置,不允许动态修改。 2. suite 套件是按设置的顺序来执行的,client 是先设置先执行,而 server 则相反。 diff --git a/content/zh/docs/kitex/Tutorials/framework-exten/trans_pipeline.md b/content/zh/docs/kitex/Tutorials/framework-exten/trans_pipeline.md index 2c03b6f0ee..54841448d3 100644 --- a/content/zh/docs/kitex/Tutorials/framework-exten/trans_pipeline.md +++ b/content/zh/docs/kitex/Tutorials/framework-exten/trans_pipeline.md @@ -36,6 +36,7 @@ type InboundHandler interface { - 服务端限流 Handler Kitex 支持连接级别和请求级别限流,限流是为了保障服务的可用性,当达到阈值应当及时限流,放到 Transport 层可以达到及时限流的目的,实现见 limiter_inbound.go。 + - 连接级别限流 OnActive(), OnInactive() - 请求级别限流 OnRead() @@ -45,9 +46,9 @@ type InboundHandler interface { - 写入透传信息 Write() - 读取透传信息 OnMessage() - + 为更明确的为使用者元信息透传的扩展能力,Kitex 单独定义了信息透传的处理接口 MetaHandler,这里会执行 MetaHandler 进行透传信息的处理。 - + ```go // MetaHandler reads or writes metadata through certain protocol. type MetaHandler interface { diff --git a/content/zh/docs/kitex/Tutorials/framework-exten/transmeta.md b/content/zh/docs/kitex/Tutorials/framework-exten/transmeta.md index cd8e610457..15a64cb347 100644 --- a/content/zh/docs/kitex/Tutorials/framework-exten/transmeta.md +++ b/content/zh/docs/kitex/Tutorials/framework-exten/transmeta.md @@ -76,4 +76,4 @@ func (ch *clientTTHeaderHandler) ReadMeta(ctx context.Context, msg remote.Messag ```go cli, err := xxxservice.NewClient(targetService, client.WithMetaHandler(transmeta.ClientTTHeaderHandler)) - ``` \ No newline at end of file + ``` diff --git a/content/zh/docs/kitex/Tutorials/framework-exten/transport.md b/content/zh/docs/kitex/Tutorials/framework-exten/transport.md index 04dd47c7ab..ad00b4ac26 100644 --- a/content/zh/docs/kitex/Tutorials/framework-exten/transport.md +++ b/content/zh/docs/kitex/Tutorials/framework-exten/transport.md @@ -41,7 +41,7 @@ type ServerTransHandlerFactory interface { } ``` -TransServer 是服务端的启动接口,ServerTransHandler 和 ClientTransHandler 分别是服务端和调用端对消息的处理接口,ByteBuffer 是读写接口。相同的 IO 模型下 TransHandler 的逻辑通常是一致的,Kitex 对同步 IO 提供了默认实现的 TransHandler,针对不一样的地方抽象出了 Extension 接口,所以在同步 IO 的场景下不需要实现完整的 TransHandler 接口,只需实现 Extension 即可。 +TransServer 是服务端的启动接口,ServerTransHandler 和 ClientTransHandler 分别是服务端和调用端对消息的处理接口,ByteBuffer 是读写接口。相同的 IO 模型下 TransHandler 的逻辑通常是一致的,Kitex 对同步 IO 提供了默认实现的 TransHandler,针对不一样的地方抽象出了 Extension 接口,所以在同步 IO 的场景下不需要实现完整的 TransHandler 接口,只需实现 Extension 即可。 ### Netpoll 的扩展 @@ -53,7 +53,7 @@ TransServer 是服务端的启动接口,ServerTransHandler 和 ClientTransHan - 服务端 - option: `WithTransServerFactory`, `WithTransHandlerFactory` + option: `WithTransServerFactory`, `WithTransHandlerFactory` ```go var opts []server.Option diff --git a/content/zh/docs/kitex/Tutorials/observability/_index.md b/content/zh/docs/kitex/Tutorials/observability/_index.md index c1a1822142..e3c4421739 100644 --- a/content/zh/docs/kitex/Tutorials/observability/_index.md +++ b/content/zh/docs/kitex/Tutorials/observability/_index.md @@ -4,5 +4,4 @@ linkTitle: "可观测性" weight: 3 date: 2023-04-19 description: > - --- diff --git a/content/zh/docs/kitex/Tutorials/observability/instrumentation.md b/content/zh/docs/kitex/Tutorials/observability/instrumentation.md index d5c54c811c..7ea2150ec8 100644 --- a/content/zh/docs/kitex/Tutorials/observability/instrumentation.md +++ b/content/zh/docs/kitex/Tutorials/observability/instrumentation.md @@ -7,6 +7,7 @@ description: Kitex 支持灵活启用基本埋点和细粒度埋点。 --- 埋点粒度: + 1. LevelDisabled 禁用埋点 2. LevelBase 仅启用基本埋点 3. LevelDetailed 启用基本埋点和细粒度埋点 @@ -14,10 +15,12 @@ description: Kitex 支持灵活启用基本埋点和细粒度埋点。 ## 埋点策略 & 埋点粒度控制 默认埋点策略: + 1. 无 tracer 时,默认 LevelDisabled -2. 有 tracer 时,默认 LevelDetailed +2. 有 tracer 时,默认 LevelDetailed 客户端埋点粒度控制: + ```go import "github.com/cloudwego/kitex/client" import "github.com/cloudwego/kitex/pkg/stats" @@ -30,6 +33,7 @@ if err != nil { ``` 服务端埋点粒度控制: + ```go import "github.com/cloudwego/kitex/server" import "github.com/cloudwego/kitex/pkg/stats" diff --git a/content/zh/docs/kitex/Tutorials/observability/monitoring.md b/content/zh/docs/kitex/Tutorials/observability/monitoring.md index a6ce108fec..a22ee3f5b5 100644 --- a/content/zh/docs/kitex/Tutorials/observability/monitoring.md +++ b/content/zh/docs/kitex/Tutorials/observability/monitoring.md @@ -69,17 +69,17 @@ func main() { Client -| 名称 | 单位 | Tags | 描述 | -|---------------------------|----|--------------------------------------|---------------------------------------| -| `kitex_client_throughput` | - | type, caller, callee, method, status | Client 端处理的请求总数 | -| `kitex_client_latency_us` | us | type, caller, callee, method, status | Client 端请求处理耗时(收到应答时间 - 发起请求时间,单位 us) | +| 名称 | 单位 | Tags | 描述 | +| ------------------------- | ---- | ------------------------------------ | ------------------------------------------------------------- | +| `kitex_client_throughput` | - | type, caller, callee, method, status | Client 端处理的请求总数 | +| `kitex_client_latency_us` | us | type, caller, callee, method, status | Client 端请求处理耗时(收到应答时间 - 发起请求时间,单位 us) | Server -| 名称 | 单位 | Tags | 描述 | -|---------------------------|----|--------------------------------------|----------------------------------------| -| `kitex_server_throughput` | - | type, caller, callee, method, status | Server 端处理的请求总数 | -| `kitex_server_latency_us` | us | type, caller, callee, method, status | Server 端请求处理耗时(处理完请求时间 - 收到请求时间,单位 us) | +| 名称 | 单位 | Tags | 描述 | +| ------------------------- | ---- | ------------------------------------ | --------------------------------------------------------------- | +| `kitex_server_throughput` | - | type, caller, callee, method, status | Server 端处理的请求总数 | +| `kitex_server_latency_us` | us | type, caller, callee, method, status | Server 端请求处理耗时(处理完请求时间 - 收到请求时间,单位 us) | 基于以上 metrics 可以实现更多复杂的数据监控,使用示例看参考 [Useful Examples](https://github.com/kitex-contrib/monitor-prometheus/?tab=readme-ov-file#useful-examples) 。 @@ -99,15 +99,15 @@ Server Server -| 名称 | 指标数据模型 | 单位 | 单位(UCUM) | 描述 | -|-----------------------|-----------|-------------|----------|--------------| -| `rpc.server.duration` | Histogram | milliseconds | `ms` | 测量请求RPC的持续时间 | +| 名称 | 指标数据模型 | 单位 | 单位(UCUM) | 描述 | +| --------------------- | ------------ | ------------ | ---------- | --------------------- | +| `rpc.server.duration` | Histogram | milliseconds | `ms` | 测量请求RPC的持续时间 | Client -| 名称 | 指标数据模型 | 单位 | 单位(UCUM) | 描述 | -|-----------------------|-----------|-------------|----------|--------------| -| `rpc.server.duration` | Histogram | milliseconds | `ms` | 测量请求RPC的持续时间 | +| 名称 | 指标数据模型 | 单位 | 单位(UCUM) | 描述 | +| --------------------- | ------------ | ------------ | ---------- | --------------------- | +| `rpc.server.duration` | Histogram | milliseconds | `ms` | 测量请求RPC的持续时间 | 通过 `rpc.server.duration` 可以计算更多的服务指标,如 R.E.D (Rate, Errors, Duration),具体示例可参考[此处](https://github.com/kitex-contrib/obs-opentelemetry/blob/main/README_CN.md#%E7%8E%B0%E5%B7%B2%E6%94%AF%E6%8C%81%E7%9A%84-mertrics)。 @@ -115,19 +115,19 @@ Client 基于 [opentelemetry-go](https://pkg.go.dev/go.opentelemetry.io/contrib/instrumentation/runtime),支持以下 runtime metrics: -| 名称 | 指标数据模型 | 单位 | 单位(UCUM) | 描述 | -| -------------------------------------- | ------------ | ---------- | ---------- |-----------------------------------| -| `process.runtime.go.cgo.calls` | Sum | - | - | 当前进程调用的cgo数量 | -| `process.runtime.go.gc.count` | Sum | - | - | 已完成的 gc 周期的数量 | -| `process.runtime.go.gc.pause_ns` | Histogram | nanosecond | `ns` | 在GC stop-the-world 中暂停的纳秒数量 | +| 名称 | 指标数据模型 | 单位 | 单位(UCUM) | 描述 | +| -------------------------------------- | ------------ | ---------- | ---------- | ------------------------------------------------ | +| `process.runtime.go.cgo.calls` | Sum | - | - | 当前进程调用的cgo数量 | +| `process.runtime.go.gc.count` | Sum | - | - | 已完成的 gc 周期的数量 | +| `process.runtime.go.gc.pause_ns` | Histogram | nanosecond | `ns` | 在GC stop-the-world 中暂停的纳秒数量 | | `process.runtime.go.gc.pause_total_ns` | Histogram | nanosecond | `ns` | 自程序启动以来,GC stop-the-world 的累计微秒计数 | -| `process.runtime.go.goroutines` | Gauge | - | - | 协程数量 | -| `process.runtime.go.lookups` | Sum | - | - | 运行时执行的指针查询的数量 | -| `process.runtime.go.mem.heap_alloc` | Gauge | bytes | `bytes` | 分配的堆对象的字节数 | -| `process.runtime.go.mem.heap_idle` | Gauge | bytes | `bytes` | 空闲(未使用)的堆内存 | -| `process.runtime.go.mem.heap_inuse` | Gauge | bytes | `bytes` | 已使用的堆内存 | -| `process.runtime.go.mem.heap_objects` | Gauge | - | - | 已分配的堆对象数量 | -| `process.runtime.go.mem.live_objects` | Gauge | - | - | 存活对象数量(Mallocs - Frees) | -| `process.runtime.go.mem.heap_released` | Gauge | bytes | `bytes` | 已交还给操作系统的堆内存 | -| `process.runtime.go.mem.heap_sys` | Gauge | bytes | `bytes` | 从操作系统获得的堆内存 | +| `process.runtime.go.goroutines` | Gauge | - | - | 协程数量 | +| `process.runtime.go.lookups` | Sum | - | - | 运行时执行的指针查询的数量 | +| `process.runtime.go.mem.heap_alloc` | Gauge | bytes | `bytes` | 分配的堆对象的字节数 | +| `process.runtime.go.mem.heap_idle` | Gauge | bytes | `bytes` | 空闲(未使用)的堆内存 | +| `process.runtime.go.mem.heap_inuse` | Gauge | bytes | `bytes` | 已使用的堆内存 | +| `process.runtime.go.mem.heap_objects` | Gauge | - | - | 已分配的堆对象数量 | +| `process.runtime.go.mem.live_objects` | Gauge | - | - | 存活对象数量(Mallocs - Frees) | +| `process.runtime.go.mem.heap_released` | Gauge | bytes | `bytes` | 已交还给操作系统的堆内存 | +| `process.runtime.go.mem.heap_sys` | Gauge | bytes | `bytes` | 从操作系统获得的堆内存 | | `runtime.uptime` | Sum | ms | `ms` | 自应用程序被初始化以来的毫秒数 | diff --git a/content/zh/docs/kitex/Tutorials/options/_index.md b/content/zh/docs/kitex/Tutorials/options/_index.md index 10983cd347..ece80bcb78 100644 --- a/content/zh/docs/kitex/Tutorials/options/_index.md +++ b/content/zh/docs/kitex/Tutorials/options/_index.md @@ -4,5 +4,4 @@ linkTitle: "Option" weight: 7 date: 2022-06-20 description: > - --- diff --git a/content/zh/docs/kitex/Tutorials/options/call_options.md b/content/zh/docs/kitex/Tutorials/options/call_options.md index 3df267049c..7bdbf67f8e 100644 --- a/content/zh/docs/kitex/Tutorials/options/call_options.md +++ b/content/zh/docs/kitex/Tutorials/options/call_options.md @@ -14,8 +14,6 @@ description: Kitex Call Option 使用说明。 resp, err := client.Call(ctx, req, callopt.WithXXX....) ``` - - ## Option 说明 ### IP 端口 - WithHostPort @@ -26,8 +24,6 @@ func WithHostPort(hostport string) Option 在本次调用阶段直接指定一个具体的 HostPort ,会覆盖掉 Resolver 的结果进行直接访问,详见[直连访问-指定 IP 和 Port 进行调用](/zh/docs/kitex/tutorials/basic-feature/visit_directly/)。 - - ### 指定 URL - WithURL ```go @@ -36,8 +32,6 @@ func WithURL(url string) Option 在本次调用阶段重新指定一个指定 URL 发起调用,详见[直连访问-指定 URL 进行调用](/zh/docs/kitex/tutorials/basic-feature/visit_directly/)。 - - ### 添加标签 - WithTag ```go @@ -50,8 +44,6 @@ func WithTag(key, val string) Option resp, err := client.Call(ctx, req,callopt.WithTag("cluster", cluster),callopt.WithTag("idc", idc)) ``` - - ### 超时设置 - WithRPCTimeout ```go @@ -60,8 +52,6 @@ func WithRPCTimeout(d time.Duration) Option 指定本次 RPC 调用的超时时间,详见[超时控制](/zh/docs/kitex/tutorials/service-governance/timeout/)。 - - ### 超时设置 - WithConnectTimeout ```go @@ -70,8 +60,6 @@ func WithConnectTimeout(d time.Duration) Option 为本次 RPC 调用设置连接超时时间,详见[超时控制](/zh/docs/kitex/tutorials/service-governance/timeout/)。 - - ### HTTP Host 设置 - WithHTTPHost ```go diff --git a/content/zh/docs/kitex/Tutorials/options/client_options.md b/content/zh/docs/kitex/Tutorials/options/client_options.md index 33ad31ca83..c49989208a 100644 --- a/content/zh/docs/kitex/Tutorials/options/client_options.md +++ b/content/zh/docs/kitex/Tutorials/options/client_options.md @@ -14,8 +14,6 @@ description: Kitex Client Option 使用说明。 client, err := echo.NewClient("targetService", client.WithXXXX...) ``` - - ## 基础 Option ### 基本信息 - WithClientBasicInfo @@ -26,8 +24,6 @@ func WithClientBasicInfo(ebi *rpcinfo.EndpointBasicInfo) Option 设置 Client 侧的 Service 信息,包括 ServiceName 和自定义的 Tags,自定义 Tag 如 Cluster、IDC、Env,无需设置 EndpointBasicInfo 的 Method 字段。强烈建议配置该 Option。 - - ### IP 端口 - WithHostPorts ```go @@ -36,8 +32,6 @@ func WithHostPorts(hostports ...string) Option 手动指定一个或者多个目标端,会覆盖掉服务发现的结果,直接直连访问。 - - ### 传输协议 - WithTransportProtocol ```go @@ -48,7 +42,6 @@ func WithTransportProtocol(tp transport.Protocol) Option 未设置 WithTransportProtocol 时,默认协议为 PurePayload。 - ### 短连接 - WithShortConnection ```go @@ -57,8 +50,6 @@ func WithShortConnection() Option 是否启用短连接,详见[连接类型-短连接](/zh/docs/kitex/tutorials/basic-feature/connection_type/)。 - - ### 长连接 - WithLongConnection ```go @@ -67,8 +58,6 @@ func WithLongConnection(cfg connpool.IdleConfig) Option 是否启用长连接,详见[连接类型-长连接](/zh/docs/kitex/tutorials/basic-feature/connection_type/)。 - - ### 多路复用 - WithMuxConnection ```go @@ -77,8 +66,6 @@ func WithMuxConnection(connNum int) Option 是否启用连接多路复用,需要同时在服务端也开启设置,详见[连接类型-连接多路复用](/zh/docs/kitex/tutorials/basic-feature/connection_type/)。 - - ### 中间件扩展 - WithMiddleware ```go @@ -87,8 +74,6 @@ func WithMiddleware(mw endpoint.Middleware) Option 添加一个中间件,在 Service 熔断和超时中间件之后执行。用法参考 [Middleware 扩展](/zh/docs/kitex/tutorials/framework-exten/middleware/)。 - - ### 中间件扩展 - WithInstanceMW ```go @@ -97,8 +82,6 @@ func WithInstanceMW(mw endpoint.Middleware) Option 用于添加一个中间件,在服务发现和负载均衡之后执行,如果有实例熔断器,会在实例熔断器后执行(如果使用了 Proxy 则不会调用到,如 Mesh 模式下)。用法参考 [Middleware 扩展](/zh/docs/kitex/tutorials/framework-exten/middleware/)。 - - ### 中间件扩展 - WithMiddlewareBuilder ```go @@ -107,8 +90,6 @@ func WithMiddlewareBuilder(mwb endpoint.MiddlewareBuilder) Option 用于创建并添加中间件,可以根据 ctx 判断场景并创建中间件。 ctx 是框架传入的包含运行时配置信息的上下文(非 RPC 调用的上下文),以便中间件初始化时能利用框架的信息。 - - ### 熔断器 - WithCircuitBreaker ```go @@ -143,8 +124,6 @@ func WithFailureRetry(p *retry.FailurePolicy) Option 设置超时重试规则,可以配置最大重试次数,累计最大耗时,重试熔断错误率阈值,DDL 中止和退避策略等,详见[请求重试](/zh/docs/kitex/tutorials/service-governance/retry/)。 - - ### 备份请求 - WithBackupRequest ```go @@ -153,8 +132,6 @@ func WithBackupRequest(p *retry.BackupPolicy) Option 设置 Backup Request 的策略,可以配置请求次数、熔断中止、链路中止等,详见[请求重试](/zh/docs/kitex/tutorials/service-governance/retry/)。 - - ### 超时设置 - WithRPCTimeout ```go @@ -163,8 +140,6 @@ func WithRPCTimeout(d time.Duration) Option 进行 RPC 超时设置,详见[超时控制](/zh/docs/kitex/tutorials/service-governance/timeout/)。 - - ### 超时设置 - WithConnectTimeout ```go @@ -173,8 +148,6 @@ func WithConnectTimeout(d time.Duration) Option 设置连接超时,详见[超时控制](/zh/docs/kitex/tutorials/service-governance/timeout/)。 - - ### 超时设置 - WithTimeoutProvider ```go @@ -183,8 +156,6 @@ func WithTimeoutProvider(p rpcinfo.TimeoutProvider) Option 添加一个 TimeoutProvider 来整体设置 RPC 超时,连接超时等策略。若同时使用了 WithRPCTimeout 或 WithConnectTimeout,那么这里的设置会被覆盖。 - - ### 指定服务 - WithDestService ```go @@ -193,18 +164,14 @@ func WithDestService(svr string) Option 指定调用目标端的服务名称,在 `NewClient` 中,第一个 string 参数就封装了这个 Option ,服务发现等场景会用到该字段。 - - ### 添加标签 - WithTag ```go -func WithTag(key, val string) Option +func WithTag(key, val string) Option ``` 为 Client 添加一些元信息,例如 idc,cluster 等,用于辅助服务发现等场景。 - - ### 埋点粒度 - WithStatsLevel ```go @@ -213,8 +180,6 @@ func WithStatsLevel(level stats.Level) Optiong 为 Client 设置埋点粒度,详见[埋点粒度](/zh/docs/kitex/tutorials/observability/tracing/)。 - - ### gRPC 相关配置 > 这类设置只对传输协议使用 gRPC 的场景生效,对 gRPC 传输进行一些参数调整。 @@ -227,8 +192,6 @@ func WithGRPCConnPoolSize(s uint32) Option 设置 gRPC 的连接池大小。只对传输协议使用 gRPC 的场景生效。 - - #### WithGRPCWriteBufferSize ```go @@ -237,8 +200,6 @@ func WithGRPCWriteBufferSize(s uint32) Option 设置 gRPC 写缓冲大小,写缓冲决定了每次批量调用底层写发送数据的大小。默认值为32KB,如果设置为0,则相当于禁用缓冲区,每次写操作都直接调用底层连接进行发送。该设置只对传输协议使用 gRPC 的场景生效。 - - #### WithGRPCReadBufferSize ```go @@ -247,8 +208,6 @@ func WithGRPCReadBufferSize(s uint32) Option 设置 gRPC 的读缓冲大小,读缓冲决定了每次批量从底层读取多少数据。默认值为32KB,如果设置为0,则相当于禁用缓冲区,每次读操作都直接从底层连接进行读操作。该设置只对传输协议使用 gRPC 的场景生效。 - - #### WithGRPCInitialWindowSize ```go @@ -257,8 +216,6 @@ func WithGRPCInitialWindowSize(s uint32) Option 设置 gRPC 每个 Stream 的初始收发窗口大小,最低为64KB,若设置的值小于最低值,则会被忽略。该设置只对传输协议使用 gRPC 的场景生效。 - - #### WithGRPCInitialConnWindowSize ```go @@ -267,8 +224,6 @@ func WithGRPCInitialConnWindowSize(s uint32) Option 设置 gRPC 单条连接上的初始窗口大小,最低为64KB,若设置的值小于最低值,则会被忽略。该设置只对传输协议使用 gRPC 的场景生效。 - - #### WithGRPCMaxHeaderListSize ```go @@ -277,8 +232,6 @@ func WithGRPCMaxHeaderListSize(s uint32) Option 设置 gRPC MaxHeaderListSize 参数,该参数决定了每次调用允许发送的header的最大条数。该设置只对传输协议使用 gRPC 的场景生效。 - - #### WithGRPCKeepaliveParams ```go @@ -288,13 +241,13 @@ func WithGRPCKeepaliveParams(kp grpc.ClientKeepalive) Option 设置 gRPC 客户端 Keepalive 的各项参数。该设置只对传输协议使用 gRPC 的场景生效。 #### WithGRPCTLSConfig + ```go func WithGRPCTLSConfig(tlsConfig *tls.Config) Option ``` 设置 gRPC 客户端的 TLS 配置。 该设置只对传输协议使用 gRPC 的场景生效。 - ## 高级 Option ### 配套扩展 - WithSuite @@ -305,8 +258,6 @@ func WithSuite(suite Suite) Option 设置一套特定配置,可根据场景进行定制,在 Suite 中配置多个 Option 和 Middleware 的组合和封装,详见 [ Suite 扩展](/zh/docs/kitex/tutorials/framework-exten/suite/)。 - - ### 代理 - WithProxy ```go @@ -315,8 +266,6 @@ func WithProxy(p proxy.ForwardProxy) Option 用于代理场景(如 Mesh Egress)做一些配置处理、返回代理地址,配置 proxy.ForwardProxy 后,框架不会执行服务发现、熔断、InstanceMWs。 - - ### 重试 - WithRetryContainer ```go @@ -327,7 +276,7 @@ func WithRetryContainer(rc *retry.Container) Option - NewRetryContainerWithCB(建议) -​ 若在已经配置熔断器的情况下,建议与 RetryContainer 复用熔断器,避免额外的统计,可以使用 NewRetryContainerWithCB ,例如下面的示例中,启用熔断器的场景,同时将熔断器透传给 RetryContainer: +​ 若在已经配置熔断器的情况下,建议与 RetryContainer 复用熔断器,避免额外的统计,可以使用 NewRetryContainerWithCB ,例如下面的示例中,启用熔断器的场景,同时将熔断器透传给 RetryContainer: ```go cbs := circuitbreak.NewCBSuite(circuitbreak.RPCInfo2Key) @@ -339,23 +288,22 @@ func WithRetryContainer(rc *retry.Container) Option ``` - NewRetryContainer - - 指定重试策略的默认 RetryContainer,其内置了一个熔断器 -- NewRetryContainerWithCBStat + - 指定重试策略的默认 RetryContainer,其内置了一个熔断器 -​ 若想对内置的熔断器进行自定义 ServiceCBKeyFunc 设置,则可以使用 NewRetryContainerWithCBStat 方法: +- NewRetryContainerWithCBStat + +​ 若想对内置的熔断器进行自定义 ServiceCBKeyFunc 设置,则可以使用 NewRetryContainerWithCBStat 方法: ```go cbs := circuitbreak.NewCBSuite(YourGenServiceCBKeyFunc) retry.NewRetryContainerWithCBStat(cbs.ServiceControl(), cbs.ServicePanel()) ``` - - ### 预热 - WithWarmingUp ```go -func WithWarmingUp(wuo *warmup.ClientOption) Option +func WithWarmingUp(wuo *warmup.ClientOption) Option ``` 设置预热。Kitex 支持了客户端预热,可以在创建客户端的时候预先初始化服务发现和连接池的相关组件,避免在首次请求时产生较大的延迟。 @@ -388,8 +336,6 @@ cli, err := myservice.NewClient(psm, client.WithWarmingUp(&warmup.ClientOption{ })) ``` - - ### 设置关闭时回调 - WithCloseCallbacks ```go @@ -398,8 +344,6 @@ func WithCloseCallbacks(callback func() error) Option 设置客户端 Close 时的回调函数。 - - ### 异常处理器 - WithErrorHandler ```go @@ -408,8 +352,6 @@ func WithErrorHandler(f func(error) error) Option 设置异常处理函数,该函数会在远程调用结束,中间件执行前被执行。 - - ### 泛化调用 - WithGeneric ```go @@ -418,8 +360,6 @@ func WithGeneric(g generic.Generic) Option 指定泛化调用类型,泛化需要结合泛化 Client/Server 使用。详见 [Kitex 泛化调用使用指南](/zh/docs/kitex/tutorials/advanced-feature/generic-call/)。 - - ### 权限控制 - WithACLRules ```go @@ -428,8 +368,6 @@ func WithACLRules(rules ...acl.RejectFunc) Option 设置 ACL 权限访问控制,该模块会在服务发现之前执行,具体用法详见[自定义访问控制](/zh/docs/kitex/tutorials/service-governance/access_control/)。 - - ### 连接池监控 - WithConnReporterEnabled ```go @@ -438,18 +376,14 @@ func WithConnReporterEnabled() Option 设置连接池状态监控,详见[连接类型-状态监控](/zh/docs/kitex/tutorials/basic-feature/connection_type/)。 - - ### 启用 HTTP 连接 - WithHTTPConnection ```go -func WithHTTPConnection() Option +func WithHTTPConnection() Option ``` 指定客户端使用 netpoll 提供的 http 连接进行 RPC 交互。 - - ## 扩展 Option ### 链路监控 - WithTracer @@ -460,8 +394,6 @@ func WithTracer(c stats.Tracer) Option 额外添加一个 Tracer 进行链路监控,详见[链路跟踪-自定义 tracer](/zh/docs/kitex/tutorials/observability/tracing/)。 - - ### 服务发现 - WithResolver ```go @@ -470,8 +402,6 @@ func WithResolver(r discovery.Resolver) Option 指定一个 Resolver 进行服务发现,用法详见[服务发现](/zh/docs/kitex/tutorials/service-governance/service_discovery/)。 - - ### HTTP 解析器 - WithHTTPResolver ```go @@ -480,18 +410,14 @@ func WithHTTPResolver(r http.Resolver) Option 指定HTTP Resolver,详见[直连访问-自定义 DNS resolver](/zh/docs/kitex/tutorials/basic-feature/visit_directly/)。 - - ### 负载均衡 - WithLoadBalancer ```go -func WithLoadBalancer(lb loadbalance.Loadbalancer, opts ...*lbcache.Options) Option +func WithLoadBalancer(lb loadbalance.Loadbalancer, opts ...*lbcache.Options) Option ``` 设置负载均衡器,详见[负载均衡](/zh/docs/kitex/tutorials/service-governance/loadbalance/)。 - - ### IO Bound 处理器 - WithBoundHandler ```go @@ -500,8 +426,6 @@ func WithBoundHandler(h remote.BoundHandler) Option 自定义 IO Bound,详见 [Transport Pipeline-Bound 扩展](/zh/docs/kitex/tutorials/framework-exten/trans_pipeline/)。 - - ### 编解码 - WithCodec ```go @@ -510,8 +434,6 @@ func WithCodec(c remote.Codec) Option 指定 Codec,详见[编解码协议扩展](/zh/docs/kitex/tutorials/framework-exten/codec/) - - ### Payload 编解码 - WithPayloadCodec ```go @@ -520,8 +442,6 @@ func WithPayloadCodec(c remote.PayloadCodec) Option 指定 PayloadCodec,详见[编解码协议扩展](/zh/docs/kitex/tutorials/framework-exten/codec/) - - ### 元信息处理 - WithMetaHandler ```go @@ -530,8 +450,6 @@ func WithMetaHandler(h remote.MetaHandler) Option 添加一个元信息处理器,用法详见[元信息传递扩展](/zh/docs/kitex/tutorials/framework-exten/transmeta/)。 - - ### 元信息处理 - WithFirstMetaHandler ```go @@ -540,18 +458,14 @@ func WithFirstMetaHandler(h remote.MetaHandler) Option 在 MetaHandler 链的最前面添加一个元信息处理器,功能同 `WithMetaHandler` 类似。 - - ### 传输设置 - WithTransHandlerFactory ```go -func WithTransHandlerFactory(f remote.ClientTransHandlerFactory) Option +func WithTransHandlerFactory(f remote.ClientTransHandlerFactory) Option ``` 自定义传输模块,详见[传输模块扩展](/zh/docs/kitex/tutorials/framework-exten/transport/)。 - - ### 诊断扩展 - WithDiagnosisService ```go @@ -560,8 +474,6 @@ func WithDiagnosisService(ds diagnosis.Service) Option 添加一个自定义的 Diagnosis Service,用来获取更多的诊断信息,详见[诊断模块扩展](/zh/docs/kitex/tutorials/framework-exten/diagnosis/)。 - - ### Dialer 扩展 - WithDialer ```go @@ -570,8 +482,6 @@ func WithDialer(d remote.Dialer) Option 手动指定 Dialer。通常情况下 Dialer 在其他配置中已经进行了配套实现,一般情况下不建议使用。 - - ### 连接池扩展 - WithConnPool ```go diff --git a/content/zh/docs/kitex/Tutorials/options/server_options.md b/content/zh/docs/kitex/Tutorials/options/server_options.md index 484f263b27..c8d34076dc 100644 --- a/content/zh/docs/kitex/Tutorials/options/server_options.md +++ b/content/zh/docs/kitex/Tutorials/options/server_options.md @@ -14,8 +14,6 @@ description: Kitex Server Option 使用说明。 svr := api.NewServer(new(DemoImpl), server.WithXXX...) ``` - - ## 基础 Option ### 基本信息 - WithServerBasicInfo @@ -26,8 +24,6 @@ func WithServerBasicInfo(ebi *rpcinfo.EndpointBasicInfo) Option 设置 Server 侧的 Service 信息,包括 ServiceName 和自定义的 Tags,自定义 Tag 如 Cluster、IDC、Env,无需设置 EndpointBasicInfo 的 Method 字段。强烈建议配置该 Option,会用于服务注册。 - - ### 指定地址 - WithServiceAddr ```go @@ -43,8 +39,6 @@ func WithServiceAddr(addr net.Addr) Option 在遇到本机有多个 IP 地址时,例如服务发现等场景需要 内网/外网 IP 地址,也可以用这个方法进行指定。 - - ### 多路复用 - WithMuxTransport ```go @@ -53,8 +47,6 @@ func WithMuxTransport() Option 服务端启用多路复用。需要配合客户端的同时开启,详见[连接类型-连接多路复用](/zh/docs/kitex/tutorials/basic-feature/connection_type/)。 - - ### 中间件扩展 - WithMiddleware ```go @@ -63,8 +55,6 @@ func WithMiddleware(mw endpoint.Middleware) Option 添加一个中间件,使用方式和 client 一致。用法参考 [Middleware 扩展](/zh/docs/kitex/tutorials/framework-exten/middleware/)。 - - ### 中间件扩展 - WithMiddlewareBuilder ```go @@ -73,8 +63,6 @@ func WithMiddlewareBuilder(mwb endpoint.MiddlewareBuilder, funcName ...string) O 用于创建并添加中间件,可以根据 ctx 判断场景并创建中间件。 ctx 是框架传入的包含运行时配置信息的上下文(非 RPC 调用的上下文),以便中间件初始化时能利用框架的信息。 - - ### 限流控制 - WithLimit ```go @@ -83,8 +71,6 @@ func WithLimit(lim *limit.Option) Option 设置限流阈值,可以设置对 QPS 和连接数的限制,该配置使用内置的限流实现,如果有定制的限流需求可以自行扩展,通过 `WithConcurrencyLimiter` 或者 `WithQPSLimiter` 集成自己的限流策略。 - - ### 超时设置 - WithReadWriteTimeout ```go @@ -95,8 +81,6 @@ func WithReadWriteTimeout(d time.Duration) Option 注意:这个功能在后续版本中可能会有改动或者删除。 - - ### 退出等待 - WithExitWaitTime ```go @@ -105,18 +89,14 @@ func WithExitWaitTime(timeout time.Duration) Option 设置服务端 Graceful Shutdown 优雅关闭的等待的时间。 - - ### 连接闲置设置 - WithMaxConnIdleTime ```go -func WithMaxConnIdleTime(timeout time.Duration) Option +func WithMaxConnIdleTime(timeout time.Duration) Option ``` 设置服务端对客户端连接的最大允许空闲的时间。 - - ### 埋点粒度 - WithStatsLevel ```go @@ -125,8 +105,6 @@ func WithStatsLevel(level stats.Level) Option 为 Server 设置埋点粒度,详见[埋点粒度](/zh/docs/kitex/tutorials/observability/tracing/)。 - - ### gRPC 相关配置 > 这类设置只对传输协议使用 gRPC 的场景生效,对 gRPC 传输进行一些参数调整。 @@ -139,8 +117,6 @@ func WithGRPCWriteBufferSize(s uint32) Option 设置 gRPC 写缓冲大小,写缓冲决定了每次批量调用底层写发送数据的大小。默认值为32KB,如果设置为0,则相当于禁用缓冲区,每次写操作都直接调用底层连接进行发送。该设置只对传输协议使用 gRPC 的场景生效。 - - #### WithGRPCReadBufferSize ```go @@ -149,8 +125,6 @@ func WithGRPCReadBufferSize(s uint32) Option 设置 gRPC 的读缓冲大小,读缓冲决定了每次批量从底层读取多少数据。默认值为32KB,如果设置为0,则相当于禁用缓冲区,每次读操作都直接从底层连接进行读操作。该设置只对传输协议使用 gRPC 的场景生效。 - - #### WithGRPCInitialWindowSize ```go @@ -159,8 +133,6 @@ func WithGRPCInitialWindowSize(s uint32) Option 设置 gRPC 每个 Stream 的初始收发窗口大小,最低为64KB,若设置的值小于最低值,则会被忽略。该设置只对传输协议使用 gRPC 的场景生效。 - - #### WithGRPCInitialConnWindowSize ```go @@ -169,8 +141,6 @@ func WithGRPCInitialConnWindowSize(s uint32) Option 设置 gRPC 单条连接上的初始窗口大小,最低为64KB,若设置的值小于最低值,则会被忽略。该设置只对传输协议使用 gRPC 的场景生效。 - - #### WithGRPCKeepaliveParams ```go @@ -179,8 +149,6 @@ func WithGRPCKeepaliveParams(kp grpc.ServerKeepalive) Option 设置 gRPC 服务端 Keepalive 的各项参数。该设置只对传输协议使用 gRPC 的场景生效。 - - #### WithGRPCKeepaliveEnforcementPolicy ```go @@ -189,8 +157,6 @@ func WithGRPCKeepaliveEnforcementPolicy(kep grpc.EnforcementPolicy) Option 设置 gRPC 服务端 Keepalive 里对于客户端策略的一些检查标准。 - - #### WithGRPCMaxConcurrentStreams ```go @@ -199,8 +165,6 @@ func WithGRPCMaxConcurrentStreams(n uint32) Option 设置 gRPC 服务端最大能接受的 Stream 数量限制。 - - #### WithGRPCMaxHeaderListSize ```go @@ -209,10 +173,6 @@ func WithGRPCMaxHeaderListSize(s uint32) Option 设置 gRPC MaxHeaderListSize 参数,该参数决定了每次调用允许发送的header的最大条数。该设置只对传输协议使用 gRPC 的场景生效。 - - - - ## 高级 Option ### 配套扩展 - WithSuite @@ -223,8 +183,6 @@ func WithSuite(suite Suite) Option 设置一套特定配置,可根据场景进行定制,在 Suite 中配置多个 Option 和 Middleware 的组合和封装,详见 [ Suite 扩展](/zh/docs/kitex/tutorials/framework-exten/suite/)。 - - ### 代理 - WithProxy ```go @@ -233,8 +191,6 @@ func WithProxy(p proxy.ReverseProxy) Option 如果服务端有代理,如 Mesh Ingress,可以通过该配置修改监听地址,用于与 Proxy 通信,比如在 proxy.ReverseProxy 修改为 uds 地址。 - - ### 注册信息 - WithRegistryInfo ```go @@ -243,8 +199,6 @@ func WithRegistryInfo(info *registry.Info) Option 自定义服务上报的注册信息,用法详见[服务发现](/zh/docs/kitex/tutorials/service-governance/service_discovery/)。 - - ### 泛化调用 - WithGeneric ```go @@ -253,8 +207,6 @@ func WithGeneric(g generic.Generic) Option 指定泛化调用类型,泛化需要结合泛化 Client/Server 使用,详见 [Kitex 泛化调用使用指南](/zh/docs/kitex/tutorials/advanced-feature/generic-call/)。 - - ### 异常处理 - WithErrorHandler ```go @@ -263,8 +215,6 @@ func WithErrorHandler(f func(error) error) Option 设置异常处理函数,该函数会在服务端 handler 执行后,中间件执行前被执行。 - - ### 权限控制 - WithACLRules ```go @@ -273,18 +223,14 @@ func WithACLRules(rules ...acl.RejectFunc) Option 设置 ACL 权限访问控制,该模块会在服务发现之前执行,具体用法详见[自定义访问控制](/zh/docs/kitex/tutorials/service-governance/access_control/)。 - - ### 退出信号 - WithExitSignal ```go -func WithExitSignal(f func() <-chan error) Option +func WithExitSignal(f func() <-chan error) Option ``` 设置服务端退出信号,Kitex 有内置实现,如果需要一些定制可以自行实现。 - - ### 端口重用 - WithReusePort ```go @@ -293,8 +239,6 @@ func WithReusePort(reuse bool) Option 设置端口重用,即是否开启底层的 TCP 端口复用机制。 - - ## 扩展 Option ### 服务发现 - WithRegistry @@ -305,8 +249,6 @@ func WithRegistry(r registry.Registry) Option 指定一个 Registry 进行服务发现的注册上报,用法详见[服务发现](/zh/docs/kitex/tutorials/service-governance/service_discovery/)。 - - ### 链路监控 - WithTracer ```go @@ -315,8 +257,6 @@ func WithTracer(c stats.Tracer) Option 额外添加一个 Tracer 进行链路监控,详见[链路跟踪-自定义 tracer](/zh/docs/kitex/tutorials/observability/tracing/)。 - - ### 编解码 - WithCodec ```go @@ -325,8 +265,6 @@ func WithCodec(c remote.Codec) Option 指定 Codec,用于需要自定义协议的场景,详见[编解码协议扩展](/zh/docs/kitex/tutorials/framework-exten/codec/)。 - - ### Payload 编解码 - WithPayloadCodec ```go @@ -335,8 +273,6 @@ func WithPayloadCodec(c remote.PayloadCodec) Option 指定 PayloadCodec,详见[编解码协议扩展](/zh/docs/kitex/tutorials/framework-exten/codec/)。 - - ### 元信息处理 - WithMetaHandler ```go @@ -345,8 +281,6 @@ func WithMetaHandler(h remote.MetaHandler) Option 添加一个元信息处理器,用于结合传输协议定制透传信息,如服务名、调用方法、机房、集群、env、TracerInfo,用法详见[元信息传递扩展](/zh/docs/kitex/tutorials/framework-exten/transmeta/)。 - - ### IO Bound 扩展 - WithBoundHandler ```go @@ -355,8 +289,6 @@ func WithBoundHandler(h remote.BoundHandler) Option 自定义 IO Bound,详见 [Transport Pipeline-Bound 扩展](/zh/docs/kitex/tutorials/framework-exten/trans_pipeline/)。 - - ### 并发限制 - WithConcurrencyLimiter ```go @@ -365,8 +297,6 @@ func WithConcurrencyLimiter(conLimit limiter.ConcurrencyLimiter) Option 设置服务端的连接数限制。 - - ### QPS 限制 - WithQPSLimiter ```go @@ -375,8 +305,6 @@ func WithQPSLimiter(qpsLimit limiter.RateLimiter) Option 设置服务端的 QPS 限制。 - - ### 限流报告器 - WithLimitReporter ```go @@ -385,8 +313,6 @@ func WithLimitReporter(r limiter.LimitReporter) Option 设置 LimitReporter,当发生 QPS 限流或连接数限流时,可以通过 LimitReporter 进行定制上报。 - - ### 传输扩展 - WithTransHandlerFactory ```go @@ -395,8 +321,6 @@ func WithTransHandlerFactory(f remote.ServerTransHandlerFactory) Option 自定义传输模块,详见[传输模块扩展](/zh/docs/kitex/tutorials/framework-exten/transport/)。 - - ### 传输扩展 - WithTransServerFactory ```go @@ -405,8 +329,6 @@ func WithTransServerFactory(f remote.TransServerFactory) Option 自定义传输模块,详见[传输模块扩展](/zh/docs/kitex/tutorials/framework-exten/transport/)。 - - ### 诊断扩展 - WithDiagnosisService ```go diff --git a/content/zh/docs/kitex/Tutorials/service-governance/_index.md b/content/zh/docs/kitex/Tutorials/service-governance/_index.md index 6f91d74c57..c6b73bafd7 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/_index.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/_index.md @@ -4,5 +4,4 @@ linkTitle: "治理特性" weight: 2 date: 2021-08-26 description: > - ---- \ No newline at end of file +--- diff --git a/content/zh/docs/kitex/Tutorials/service-governance/circuitbreaker.md b/content/zh/docs/kitex/Tutorials/service-governance/circuitbreaker.md index e003485f1e..c1fc134e8b 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/circuitbreaker.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/circuitbreaker.md @@ -2,7 +2,7 @@ title: "熔断" date: 2023-10-24 weight: 5 -keywords: ["Kitex","熔断","熔断器"] +keywords: ["Kitex", "熔断", "熔断器"] description: "Kitex 熔断使用指南、原理介绍。" --- @@ -29,17 +29,17 @@ func GenServiceCBKeyFunc(ri rpcinfo.RPCInfo) string { } func main() { - // build a new CBSuite with + // build a new CBSuite with cbs := circuitbreak.NewCBSuite(GenServiceCBKeyFunc) var opts []client.Option - + // add to the client options opts = append(opts, client.WithCircuitBreaker(cbs)) - - // init client + + // init client cli, err := echoservice.NewClient(targetService, opts...) - + // update circuit breaker config for a certain key (should be consistent with GenServiceCBKeyFunc) // this can be called at any time, and will take effect for following requests cbs.UpdateServiceCBConfig("fromServiceName/toServiceName/method", circuitbreak.CBConfig{ @@ -61,10 +61,12 @@ Kitex 大部分服务治理模块都是通过 middleware 集成,熔断也是 - 服务粒度熔断 - 按照服务粒度进行熔断统计,通过 WithMiddleware 添加。服务粒度的具体划分取决于 Circuit Breaker Key,既熔断统计的 key,初始化 CBSuite 时需要传入 **GenServiceCBKeyFunc**,默认提供的是 circuitbreak.RPCInfo2Key ,该 key 的格式是 `fromServiceName/toServiceName/method`,即按照方法级别的异常做熔断统计。 + - 实例粒度熔断 - 按照实例粒度进行熔断统计,主要用于解决单实例异常问题,如果触发了实例级别熔断,框架会自动重试。 - 注意,框架自动重试的前提是需要通过 **WithInstanceMW** 添加,WithInstanceMW 添加的 middleware 会在负载均衡后执行。 + - 熔断阈值及**阈值变更** - 默认的熔断阈值是 `ErrRate: 0.5, MinSample: 200`,错误率达到 50% 触发熔断,同时要求统计量 >200。若要调整阈值,调用 CBSuite 的 `UpdateServiceCBConfig` 和 `UpdateInstanceCBConfig` 来更新 Key 的阈值。 @@ -85,7 +87,7 @@ Kitex 大部分服务治理模块都是通过 middleware 集成,熔断也是 ### 熔断策略 -**熔断器的思路很简单:根据****RPC****的成功失败情况,限制对下游的访问;** +**熔断器的思路很简单:根据\*\***RPC\***\*的成功失败情况,限制对下游的访问;** 通常熔断器分为三个时期: CLOSED、OPEN、HALFOPEN; @@ -170,6 +172,7 @@ Options 中的 BucketTime 和 BucketNums,就分别对应了每个桶维护的 - (1) 检测到 0 号桶已经过期,将其丢弃; - (2) 创建新的 10 号桶,对应 [10S,11S); - (3) 将该次 Succ 放入 10 号桶内; + - 在 10.2S 时,你执行 Successes() 查询窗口内成功数,则你得到的实际统计值是 [1S,10.2S) 的数据,而不是 [0.2S,10.2S); 如果使用分桶计数的办法,这样的抖动是无法避免的,比较折中的一个办法是将桶的个数增多,可以降低抖动的影响; diff --git a/content/zh/docs/kitex/Tutorials/service-governance/config-center/_index.md b/content/zh/docs/kitex/Tutorials/service-governance/config-center/_index.md index 2a4137d100..3c56894525 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/config-center/_index.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/config-center/_index.md @@ -5,7 +5,6 @@ date: 2023-11-29 weight: 2 keywords: ["配置中心"] description: "kitex-contrib 提供对配置中心的扩展" - --- ## Kitex 对接配置中心 @@ -18,8 +17,8 @@ kitex-contrib 提供了对于社区主流配置中心的拓展,实现了动态 目前支持的配置中心有: -| 配置中心 | 仓库 | -|:---------:|:--------------------------------------------------------------------:| +| 配置中心 | 仓库 | +| :-------: | :------------------------------------------------------------------: | | nacos | [config-nacos](https://github.com/kitex-contrib/config-nacos) | | etcd | [config-etcd](https://github.com/kitex-contrib/config-etcd) | | apollo | [config-apollo](https://github.com/kitex-contrib/config-apollo) | @@ -32,11 +31,13 @@ kitex-contrib 提供了对于社区主流配置中心的拓展,实现了动态 在对接配置中心的过程中,使用了 Suite(套件)来进行第三方的拓展。 Suite 的定义如下: + ```go type Suite interface { Options() []Option } ``` + Server 端和 Client 端都是通过 WithSuite 这个方法来注入新的套件。 更多关于 Suite 的介绍请见 [Suite](../../framework-exten/suite) diff --git a/content/zh/docs/kitex/Tutorials/service-governance/config-center/apollo.md b/content/zh/docs/kitex/Tutorials/service-governance/config-center/apollo.md index 0dbc872600..ff9d0077fb 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/config-center/apollo.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/config-center/apollo.md @@ -2,15 +2,16 @@ title: "Apollo" date: 2023-12-12 weight: 2 -keywords: ["配置中心扩展","apollo"] +keywords: ["配置中心扩展", "apollo"] description: "使用 apollo作为 Kitex 的服务治理配置中心" - --- + ## 安装 `go get github.com/kitex-contrib/config-apollo` ## Suite + apollo 的配置中心适配器,kitex 通过 `WithSuite` 将 apollo 中的配置转换为 kitex 的治理特性配置。 以下是完整的使用样例: @@ -80,6 +81,7 @@ func main() { ``` ### Client + ```go type ApolloClientSuite struct { apolloClient apollo.Client // config-apollo 中的 apollo client @@ -88,6 +90,7 @@ type ApolloClientSuite struct { opts utils.Options // 用户自定义配置函数 } ``` + 函数签名: `func NewSuite(service, client string, cli apollo.Client,options ...utils.Option) *ApolloClientSuite` @@ -168,6 +171,7 @@ type ConfigParser interface { 示例代码: 设置解析 json 类型的配置 + ```go package main @@ -194,6 +198,7 @@ func main() { ## Apollo 配置 ### Options 结构体 + ```go type Options struct { ConfigServerURL string @@ -205,7 +210,9 @@ type Options struct { ConfigParser ConfigParser } ``` + ### Options 默认值 + ```go type ConfigParamConfig struct { Category string @@ -213,22 +220,23 @@ type ConfigParamConfig struct { ServerServiceName string } ``` + kitex-contrib/config-apollo 中设计 namespace 的类型为 properties ,key 的格式参考如下: ClientKeyFormat 或 ServerKeyFormat ,value 固定为 json 格式 -| 参数 | 变量默认值 | 作用 | -| :------------------------ | :--------------------------------: | --------------------------------- | -| ConfigServerURL | 127.0.0.1:8080 | apollo config service 地址 | -| AppID | KitexApp | apollo 的 appid (唯一性约束) | -| ClientKeyFormat | {{.ClientServiceName}}.{{.ServerServiceName}} | 使用 go [template](https://pkg.go.dev/text/template) 语法渲染生成对应的 ID, 使用 `ClientServiceName` `ServiceName` 两个元数据 (长度不超过128个字符) | -| ServerKeyFormat | {{.ServerServiceName}} | 使用 go [template](https://pkg.go.dev/text/template) 语法渲染生成对应的 ID, 使用 `ServiceName` ` 单个元数据 (长度不超过128个字符) | -| Cluster | default | 使用默认值,用户可根据需要赋值 (长度不超过32个字符) | -| ConfigParser | defaultConfigParser | 默认解析器,默认为解析 json 格式的数据(目前设计仅支持json解析) | +| 参数 | 变量默认值 | 作用 | +| :-------------- | :-------------------------------------------: | --------------------------------------------------------------------------------------------------------------------------------------------------- | +| ConfigServerURL | 127.0.0.1:8080 | apollo config service 地址 | +| AppID | KitexApp | apollo 的 appid (唯一性约束) | +| ClientKeyFormat | {{.ClientServiceName}}.{{.ServerServiceName}} | 使用 go [template](https://pkg.go.dev/text/template) 语法渲染生成对应的 ID, 使用 `ClientServiceName` `ServiceName` 两个元数据 (长度不超过128个字符) | +| ServerKeyFormat | {{.ServerServiceName}} | 使用 go [template](https://pkg.go.dev/text/template) 语法渲染生成对应的 ID, 使用 `ServiceName` ` 单个元数据 (长度不超过128个字符) | +| Cluster | default | 使用默认值,用户可根据需要赋值 (长度不超过32个字符) | +| ConfigParser | defaultConfigParser | 默认解析器,默认为解析 json 格式的数据(目前设计仅支持json解析) | ### 治理策略 下面例子中的 namespace 使用策略固定值, APPID 以及 Cluster 均使用默认值,服务名称为 ServiceName,客户端名称为 ClientName -#### 限流 +#### 限流 Category=limit @@ -236,23 +244,24 @@ Category=limit [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/limiter/item_limiter.go#L33) -|字段|说明| -|----|----| -|connection_limit|最大并发数量| -|qps_limit|每 100ms 内的最大请求数量| +| 字段 | 说明 | +| ---------------- | ------------------------- | +| connection_limit | 最大并发数量 | +| qps_limit | 每 100ms 内的最大请求数量 | 例子: > namespace: `limit` -> +> > key: `ServiceName` ```json { - "connection_limit": 100, - "qps_limit": 2000 + "connection_limit": 100, + "qps_limit": 2000 } ``` + 注: - 限流配置的粒度是 Server 全局,不分 client、method @@ -265,57 +274,58 @@ Category=retry [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/retry/policy.go#L63) -|参数|说明| -|----|----| -|type| 0: failure_policy 1: backup_policy| -|failure_policy.backoff_policy| 可以设置的策略: `fixed` `none` `random` | +| 参数 | 说明 | +| ----------------------------- | ---------------------------------------- | +| type | 0: failure_policy 1: backup_policy | +| failure_policy.backoff_policy | 可以设置的策略: `fixed` `none` `random` | 例子: > namespace: `retry` -> +> > key: `ClientName.ServiceName` ```json { - "*": { - "enable": true, - "type": 0, - "failure_policy": { - "stop_policy": { - "max_retry_times": 3, - "max_duration_ms": 2000, - "cb_policy": { - "error_rate": 0.3 - } - }, - "backoff_policy": { - "backoff_type": "fixed", - "cfg_items": { - "fix_ms": 50 - } - }, - "retry_same_node": false + "*": { + "enable": true, + "type": 0, + "failure_policy": { + "stop_policy": { + "max_retry_times": 3, + "max_duration_ms": 2000, + "cb_policy": { + "error_rate": 0.3 } - }, - "echo": { - "enable": true, - "type": 1, - "backup_policy": { - "retry_delay_ms": 100, - "retry_same_node": false, - "stop_policy": { - "max_retry_times": 2, - "max_duration_ms": 300, - "cb_policy": { - "error_rate": 0.2 - } - } + }, + "backoff_policy": { + "backoff_type": "fixed", + "cfg_items": { + "fix_ms": 50 } + }, + "retry_same_node": false } + }, + "echo": { + "enable": true, + "type": 1, + "backup_policy": { + "retry_delay_ms": 100, + "retry_same_node": false, + "stop_policy": { + "max_retry_times": 2, + "max_duration_ms": 300, + "cb_policy": { + "error_rate": 0.2 + } + } + } + } } ``` -注:retry.Container 内置支持用 * 通配符指定默认配置(详见 [getRetryer](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/retry/retryer.go#L240) 方法) + +注:retry.Container 内置支持用 \* 通配符指定默认配置(详见 [getRetryer](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/retry/retryer.go#L240) 方法) #### 超时 @@ -326,13 +336,13 @@ Category=rpc_timeout 例子: > namespace: `rpc_timeout` -> +> > key: `ClientName.ServiceName` ```json { "*": { - "conn_timeout_ms": 100, + "conn_timeout_ms": 100, "rpc_timeout_ms": 3000 }, "echo": { @@ -341,6 +351,7 @@ Category=rpc_timeout } } ``` + 注:kitex 的熔断实现目前不支持修改全局默认配置(详见 [initServiceCB](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/circuitbreak/cbsuite.go#L195)) #### 熔断 @@ -349,13 +360,14 @@ Category=circuit_break [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/circuitbreak/item_circuit_breaker.go#L30) -|参数|说明| -|----|----| -|min_sample| 最小的统计样本数| +| 参数 | 说明 | +| ---------- | ---------------- | +| min_sample | 最小的统计样本数 | + 例子: > namespace: `circuit_break` -> +> > key: `ClientName.ServiceName` ```json @@ -363,8 +375,8 @@ echo 方法使用下面的配置(0.3、100),其他方法使用全局默认 { "echo": { "enable": true, - "err_rate": 0.3, - "min_sample": 100 + "err_rate": 0.3, + "min_sample": 100 } } ``` diff --git a/content/zh/docs/kitex/Tutorials/service-governance/config-center/consul.md b/content/zh/docs/kitex/Tutorials/service-governance/config-center/consul.md index 2e26a0b64e..a4bda58a3d 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/config-center/consul.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/config-center/consul.md @@ -216,6 +216,7 @@ type ConfigParser interface { 示例代码: 设置解析 yaml 类型的配置 + ```go package main @@ -258,21 +259,19 @@ type Options struct { ### Options 默认值 - -| 参数 | 变量默认值 | 作用 | -| ---------------- |-------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------| -| Addr | 127.0.0.1:8500 | Consul 服务器地址 | -| Prefix | /KitexConfig | Consul 的 Prefix | +| 参数 | 变量默认值 | 作用 | +| ---------------- | ----------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Addr | 127.0.0.1:8500 | Consul 服务器地址 | +| Prefix | /KitexConfig | Consul 的 Prefix | | ServerPathFormat | {{.ServerServiceName}}/{{.Category}} | 使用 go [template](https://pkg.go.dev/text/template) 语法渲染生成对应的 ID, 使用 `ServiceName` `Category` 两个元数据,用于和 Prefix 组成 consul 中配置的 key | | ClientPathFormat | {{.ClientServiceName}}/{{.ServerServiceName}}/{{.Category}} | 使用 go [template](https://pkg.go.dev/text/template) 语法渲染生成对应的 ID, 使用 `ClientServiceName` `ServiceName` `Category` 三个元数据,用于和 Prefix 组成 consul 中配置的 key | -| DataCenter | dc1 | Consul 默认数据中心 | -| Timeout | 5 \* time.Second | 5s 超时时间 | -| NamespaceId | | Consul 的 Namespace Id | -| Token | | Consul 服务的认证 Token | -| Partition | | Consul 的 Partition | -| LoggerConfig | NULL | 默认日志 | -| ConfigParser | defaultConfigParser | 默认解析器,默认为解析 json 与 yaml 格式的数据 | - +| DataCenter | dc1 | Consul 默认数据中心 | +| Timeout | 5 \* time.Second | 5s 超时时间 | +| NamespaceId | | Consul 的 Namespace Id | +| Token | | Consul 服务的认证 Token | +| Partition | | Consul 的 Partition | +| LoggerConfig | NULL | 默认日志 | +| ConfigParser | defaultConfigParser | 默认解析器,默认为解析 json 与 yaml 格式的数据 | ### 治理策略 diff --git a/content/zh/docs/kitex/Tutorials/service-governance/config-center/etcd.md b/content/zh/docs/kitex/Tutorials/service-governance/config-center/etcd.md index 50e8e6dab3..06d6748bc5 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/config-center/etcd.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/config-center/etcd.md @@ -2,15 +2,16 @@ title: "Etcd" date: 2023-11-29 weight: 1 -keywords: ["配置中心扩展","etcd"] +keywords: ["配置中心扩展", "etcd"] description: "使用 etcd 作为 Kitex 的服务治理配置中心" - --- + ## 安装 `go get github.com/kitex-contrib/config-etcd` ## Suite + etcd 的配置中心适配器,kitex 通过 `WithSuite` 将 etcd 中的配置转换为 kitex 的治理特性配置。 以下是完整的使用样例: @@ -74,6 +75,7 @@ func main() { ``` ### Client + ```go type EtcdServerSuite struct { uid int64 @@ -82,6 +84,7 @@ type EtcdServerSuite struct { opts utils.Options } ``` + 函数签名: `func NewSuite(service,client string, cli etcd.Client, opts ...utils.Option,) *EtcdServerSuite` @@ -163,6 +166,7 @@ type ConfigParser interface { 示例代码: 设置解析 yaml 类型的配置 + ```go package main @@ -186,6 +190,7 @@ func main() { ## Etcd 配置 ### Options 结构体 + ```go type Options struct { Node []string @@ -197,39 +202,44 @@ type Options struct { ConfigParser ConfigParser } ``` + ### Options 默认值 + ```go type Key struct { Prefix string Path string } ``` + etcd 中的 key 由 prefix 和 path 组成,prefix 为前缀,path 为路径。 -| 参数 | 变量默认值 | 作用 | -|------------------|-------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------| -| Node | 127.0.0.1:2379 | Etcd 服务器节点 | -| Prefix | /KitexConfig | Etcd 中的 prefix | +| 参数 | 变量默认值 | 作用 | +| ---------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Node | 127.0.0.1:2379 | Etcd 服务器节点 | +| Prefix | /KitexConfig | Etcd 中的 prefix | | ClientPathFormat | {{.ClientServiceName}}/{{.ServerServiceName}}/{{.Category}} | 使用 go [template](https://pkg.go.dev/text/template) 语法渲染生成对应的 ID, 使用 `ClientServiceName` `ServiceName` `Category` 三个元数据,用于和 Prefix 组成 etcd 中配置的 key | | ServerPathFormat | {{.ServerServiceName}}/{{.Category}} | 使用 go [template](https://pkg.go.dev/text/template) 语法渲染生成对应的 ID, 使用 `ServiceName` `Category` 两个元数据,用于和 Prefix 组成 etcd 中配置的 key | -| Timeout | 5 * time.Second | 五秒超时时间 | -| LoggerConfig | NULL | 默认日志 | -| ConfigParser | defaultConfigParser | 默认解析器,默认为解析 json 格式的数据 | - +| Timeout | 5 \* time.Second | 五秒超时时间 | +| LoggerConfig | NULL | 默认日志 | +| ConfigParser | defaultConfigParser | 默认解析器,默认为解析 json 格式的数据 | ### 治理策略 + 下面例子中的 configPath 以及 configPrefix 均使用默认值,服务名称为 ServiceName,客户端名称为 ClientName。 -#### 限流 +#### 限流 + Category=limit + > 限流目前只支持服务端,所以 ClientServiceName 为空。 [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/limiter/item_limiter.go#L33) -| 字段 | 说明 | -|------------------|------------------| -| connection_limit | 最大并发数量 | -| qps_limit | 每 100ms 内的最大请求数量 | +| 字段 | 说明 | +| ---------------- | ------------------------- | +| connection_limit | 最大并发数量 | +| qps_limit | 每 100ms 内的最大请求数量 | 例子: @@ -237,25 +247,27 @@ Category=limit ```json { - "connection_limit": 100, - "qps_limit": 2000 + "connection_limit": 100, + "qps_limit": 2000 } ``` + 注: - 限流配置的粒度是 Server 全局,不分 client、method。 - 「未配置」或「取值为 0」表示不开启。 - connection_limit 和 qps_limit 可以独立配置,例如 connection_limit = 100, qps_limit = 0。 -#### 重试 +#### 重试 + Category=retry [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/retry/policy.go#L63) -| 参数 | 说明 | -|-------------------------------|------------------------------------| -| type | 0: failure_policy 1: backup_policy | -| failure_policy.backoff_policy | 可以设置的策略: `fixed` `none` `random` | +| 参数 | 说明 | +| ----------------------------- | ---------------------------------------- | +| type | 0: failure_policy 1: backup_policy | +| failure_policy.backoff_policy | 可以设置的策略: `fixed` `none` `random` | 例子: @@ -263,46 +275,48 @@ Category=retry ```json { - "*": { - "enable": true, - "type": 0, - "failure_policy": { - "stop_policy": { - "max_retry_times": 3, - "max_duration_ms": 2000, - "cb_policy": { - "error_rate": 0.3 - } - }, - "backoff_policy": { - "backoff_type": "fixed", - "cfg_items": { - "fix_ms": 50 - } - }, - "retry_same_node": false + "*": { + "enable": true, + "type": 0, + "failure_policy": { + "stop_policy": { + "max_retry_times": 3, + "max_duration_ms": 2000, + "cb_policy": { + "error_rate": 0.3 + } + }, + "backoff_policy": { + "backoff_type": "fixed", + "cfg_items": { + "fix_ms": 50 } - }, - "echo": { - "enable": true, - "type": 1, - "backup_policy": { - "retry_delay_ms": 100, - "retry_same_node": false, - "stop_policy": { - "max_retry_times": 2, - "max_duration_ms": 300, - "cb_policy": { - "error_rate": 0.2 - } - } + }, + "retry_same_node": false + } + }, + "echo": { + "enable": true, + "type": 1, + "backup_policy": { + "retry_delay_ms": 100, + "retry_same_node": false, + "stop_policy": { + "max_retry_times": 2, + "max_duration_ms": 300, + "cb_policy": { + "error_rate": 0.2 } + } } + } } ``` -注:retry.Container 内置支持用 * 通配符指定默认配置(详见 [getRetryer](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/retry/retryer.go#L240) 方法)。 -#### 超时 +注:retry.Container 内置支持用 \* 通配符指定默认配置(详见 [getRetryer](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/retry/retryer.go#L240) 方法)。 + +#### 超时 + Category=rpc_timeout [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/rpctimeout/item_rpc_timeout.go#L42) @@ -314,7 +328,7 @@ Category=rpc_timeout ```json { "*": { - "conn_timeout_ms": 100, + "conn_timeout_ms": 100, "rpc_timeout_ms": 3000 }, "echo": { @@ -323,16 +337,18 @@ Category=rpc_timeout } } ``` + 注:kitex 的熔断实现目前不支持修改全局默认配置(详见 [initServiceCB](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/circuitbreak/cbsuite.go#L195))。 #### 熔断 + Category=circuit_break [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/circuitbreak/item_circuit_breaker.go#L30) -| 参数 | 说明 | -|------------|----------| -| min_sample | 最小的统计样本数 | +| 参数 | 说明 | +| ---------- | ---------------- | +| min_sample | 最小的统计样本数 | 例子: @@ -351,4 +367,5 @@ echo 方法使用下面的配置(0.3、100),其他方法使用全局默认 ``` ## 兼容性 + 因为 grpc 兼容的问题,Go 的版本必须 >= 1.19 diff --git a/content/zh/docs/kitex/Tutorials/service-governance/config-center/file.md b/content/zh/docs/kitex/Tutorials/service-governance/config-center/file.md index f7a05cbd5f..00bcf5bfce 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/config-center/file.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/config-center/file.md @@ -2,14 +2,14 @@ title: "File" date: 2023-12-18 weight: 4 -keywords: ["配置中心扩展","file"] +keywords: ["配置中心扩展", "file"] description: "使用 本地文件 作为 Kitex 的服务治理配置中心" - --- + ## 支持文件类型 -| json | yaml | -| --- | --- | +| json | yaml | +| -------- | -------- | | ✔ | ✔ | ## 安装 @@ -17,6 +17,7 @@ description: "使用 本地文件 作为 Kitex 的服务治理配置中心" `go get github.com/kitex-contrib/config-file` ## Suite + 本地文件 的配置中心适配器,kitex 通过 `WithSuite` 将 本地文件 中的配置转换为 kitex 的治理特性配置。 使用方法可以分为两个步骤 @@ -108,12 +109,14 @@ func main() { ``` ### Client + ```go type FileConfigClientSuite struct { watcher monitor.ConfigMonitor service string } ``` + 函数签名: `func NewSuite(service, key string, watcher filewatcher.FileWatcher,opts ...utils.Option)*FileConfigClientSuite` @@ -256,6 +259,7 @@ type ConfigParser interface { 示例代码: 扩展解析 YAML 类型。 + ```go // 由用户自定义 type MyParser struct{} @@ -297,26 +301,28 @@ client, err := echo.NewClient( 在后续样例中,我们设定服务名称为 `ServiceName`,客户端名称为 `ClientName`。 #### 限流 + Category=limit > 限流目前只支持服务端,所以只需要设置服务端的 ServiceName。 [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/limiter/item_limiter.go#L33) -|字段|说明| -|----|----| -|connection_limit|最大并发数量| -|qps_limit|每 100ms 内的最大请求数量| +| 字段 | 说明 | +| ---------------- | ------------------------- | +| connection_limit | 最大并发数量 | +| qps_limit | 每 100ms 内的最大请求数量 | 样例: + ```json { - "ServiceName": { - "limit": { - "connection_limit": 300, - "qps_limit": 200 - } + "ServiceName": { + "limit": { + "connection_limit": 300, + "qps_limit": 200 } + } } ``` @@ -328,14 +334,15 @@ Category=limit - 可以在一个 json 内编写多个服务的不同限流策略,只需要 filewatch 监控同一个文件,然后传入不同的 key 即可,如样例所示,key 即为`ServiceName` #### 重试 + Category=retry [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/retry/policy.go#L63) -|参数|说明| -|----|----| -|type| 0: failure_policy 1: backup_policy| -|failure_policy.backoff_policy| 可以设置的策略: `fixed` `none` `random` | +| 参数 | 说明 | +| ----------------------------- | ---------------------------------------- | +| type | 0: failure_policy 1: backup_policy | +| failure_policy.backoff_policy | 可以设置的策略: `fixed` `none` `random` | 样例: @@ -343,42 +350,44 @@ Category=retry ```json { - "ClientName/ServiceName": { - "retry": { - "*": { - "enable": true, - "type": 0, - "failure_policy": { - "stop_policy": { - "max_retry_times": 3, - "max_duration_ms": 2000, - "cb_policy": { - "error_rate": 0.2 - } - } - } - }, - "Echo": { - "enable": true, - "type": 1, - "backup_policy": { - "retry_delay_ms": 200, - "stop_policy": { - "max_retry_times": 2, - "max_duration_ms": 1000, - "cb_policy": { - "error_rate": 0.3 - } - } - } + "ClientName/ServiceName": { + "retry": { + "*": { + "enable": true, + "type": 0, + "failure_policy": { + "stop_policy": { + "max_retry_times": 3, + "max_duration_ms": 2000, + "cb_policy": { + "error_rate": 0.2 + } + } + } + }, + "Echo": { + "enable": true, + "type": 1, + "backup_policy": { + "retry_delay_ms": 200, + "stop_policy": { + "max_retry_times": 2, + "max_duration_ms": 1000, + "cb_policy": { + "error_rate": 0.3 } + } } + } } + } } ``` -注:retry.Container 内置支持用 * 通配符指定默认配置(详见 [getRetryer](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/retry/retryer.go#L240) 方法) + +注:retry.Container 内置支持用 \* 通配符指定默认配置(详见 [getRetryer](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/retry/retryer.go#L240) 方法) #### 超时 + Category=rpc_timeout [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/rpctimeout/item_rpc_timeout.go#L42) @@ -389,29 +398,30 @@ Category=rpc_timeout ```json { - "ClientName/ServiceName": { - "timeout": { - "*": { - "conn_timeout_ms": 100, - "rpc_timeout_ms": 2000 - }, - "Pay": { - "conn_timeout_ms": 50, - "rpc_timeout_ms": 1000 - } - }, + "ClientName/ServiceName": { + "timeout": { + "*": { + "conn_timeout_ms": 100, + "rpc_timeout_ms": 2000 + }, + "Pay": { + "conn_timeout_ms": 50, + "rpc_timeout_ms": 1000 + } } + } } ``` #### 熔断 + Category=circuit_break [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/circuitbreak/item_circuit_breaker.go#L30) -|参数|说明| -|----|----| -|min_sample|最小的统计样本数| +| 参数 | 说明 | +| ---------- | ---------------- | +| min_sample | 最小的统计样本数 | 样例: echo 方法使用下面的配置(0.3、100),其他方法使用全局默认配置(0.5、200) @@ -420,18 +430,20 @@ echo 方法使用下面的配置(0.3、100),其他方法使用全局默认 ```json { - "ClientName/ServiceName": { - "circuitbreaker": { - "Echo": { - "enable": true, - "err_rate": 0.3, - "min_sample": 100 - } - }, + "ClientName/ServiceName": { + "circuitbreaker": { + "Echo": { + "enable": true, + "err_rate": 0.3, + "min_sample": 100 + } } + } } ``` + 注:kitex 的熔断实现目前不支持修改全局默认配置(详见 [initServiceCB](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/circuitbreak/cbsuite.go#L195)) + #### 更多信息 更多示例请参考 [example](https://github.com/kitex-contrib/config-file/tree/main/example) @@ -444,56 +456,57 @@ echo 方法使用下面的配置(0.3、100),其他方法使用全局默认 ```json { - "ClientName/ServiceName": { - "timeout": { - "*": { - "conn_timeout_ms": 100, - "rpc_timeout_ms": 2000 - }, - "Pay": { - "conn_timeout_ms": 50, - "rpc_timeout_ms": 1000 - } - }, - "circuitbreaker": { - "Echo": { - "enable": true, - "err_rate": 0.3, - "min_sample": 100 + "ClientName/ServiceName": { + "timeout": { + "*": { + "conn_timeout_ms": 100, + "rpc_timeout_ms": 2000 + }, + "Pay": { + "conn_timeout_ms": 50, + "rpc_timeout_ms": 1000 + } + }, + "circuitbreaker": { + "Echo": { + "enable": true, + "err_rate": 0.3, + "min_sample": 100 + } + }, + "retry": { + "*": { + "enable": true, + "type": 0, + "failure_policy": { + "stop_policy": { + "max_retry_times": 3, + "max_duration_ms": 2000, + "cb_policy": { + "error_rate": 0.2 } - }, - "retry": { - "*": { - "enable": true, - "type": 0, - "failure_policy": { - "stop_policy": { - "max_retry_times": 3, - "max_duration_ms": 2000, - "cb_policy": { - "error_rate": 0.2 - } - } - } - }, - "Echo": { - "enable": true, - "type": 1, - "backup_policy": { - "retry_delay_ms": 200, - "stop_policy": { - "max_retry_times": 2, - "max_duration_ms": 1000, - "cb_policy": { - "error_rate": 0.3 - } - } - } + } + } + }, + "Echo": { + "enable": true, + "type": 1, + "backup_policy": { + "retry_delay_ms": 200, + "stop_policy": { + "max_retry_times": 2, + "max_duration_ms": 1000, + "cb_policy": { + "error_rate": 0.3 } + } } + } } + } } ``` ### 兼容性 + 项目中使用了`sync/atomic`在 1.19 版本加入的新特性,因此Go 的版本必须 >= 1.19 diff --git a/content/zh/docs/kitex/Tutorials/service-governance/config-center/nacos.md b/content/zh/docs/kitex/Tutorials/service-governance/config-center/nacos.md index fd4161ff6c..b7c83ae14e 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/config-center/nacos.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/config-center/nacos.md @@ -2,16 +2,17 @@ title: "Nacos" date: 2023-12-14 weight: 3 -keywords: ["配置中心扩展","Nacos"] +keywords: ["配置中心扩展", "Nacos"] description: "使用 Nacos 作为 Kitex 的服务治理配置中心" --- ## 安装 + `go get github.com/kitex-contrib/config-nacos` ## Suite -Nacos 的配置中心适配器,Kitex 通过 Nacos 中的配置转换为 Kitex 的治理特性配置。 +Nacos 的配置中心适配器,Kitex 通过 Nacos 中的配置转换为 Kitex 的治理特性配置。 ### Server @@ -167,6 +168,7 @@ type ConfigParser interface { 示例代码: 设置解析 xml 类型的配置 + ```go package main @@ -204,7 +206,7 @@ func main() { ## Nacos 配置 -根据 Options 的参数初始化 client,建立链接之后 suite 会根据 `Group` 以及 `ServerDataIDFormat` 或者 `ClientDataIDFormat` 订阅对应的配置并动态更新自身策略,具体参数参考下面 `Options` 变量。 +根据 Options 的参数初始化 client,建立链接之后 suite 会根据 `Group` 以及 `ServerDataIDFormat` 或者 `ClientDataIDFormat` 订阅对应的配置并动态更新自身策略,具体参数参考下面 `Options` 变量。 配置的格式默认支持 `json` 和 `yaml`,可以使用函数 [SetParser](https://github.com/kitex-contrib/config-nacos/blob/eb006978517678dd75a81513142d3faed6a66f8d/nacos/nacos.go#L68) 进行自定义格式解析方式,并在 `NewSuite` 的时候使用 `CustomFunction` 函数修改订阅函数的格式。 @@ -214,29 +216,31 @@ func main() { ### Options 默认值 -| 参数 | 变量默认值 | 作用 | -| ------------------------- | ---------------------------------- | --------------------------------- | -| Address | 127.0.0.1 | nacos 服务器地址, 如果参数为空使用 serverAddr 环境变量值 | -| Port | 8848 | nacos 服务器端口, 如果参数为空使用 serverPort 环境变量值 | -| NamespaceID | | nacos 中的 namespace Id, 如果参数为空使用 namespace 环境变量值 | -| ClientDataIDFormat | {{.ClientServiceName}}.{{.ServerServiceName}}.{{.Category}} | 使用 go [template](https://pkg.go.dev/text/template) 语法渲染生成对应的 ID, 使用 `ClientServiceName` `ServiceName` `Category` 三个元数据 | -| ServerDataIDFormat | {{.ServerServiceName}}.{{.Category}} | 使用 go [template](https://pkg.go.dev/text/template) 语法渲染生成对应的 ID, 使用 `ServiceName` `Category` 两个元数据 | -| Group | DEFAULT_GROUP | 使用固定值,也可以动态渲染,用法同 DataIDFormat | +| 参数 | 变量默认值 | 作用 | +| ------------------ | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | +| Address | 127.0.0.1 | nacos 服务器地址, 如果参数为空使用 serverAddr 环境变量值 | +| Port | 8848 | nacos 服务器端口, 如果参数为空使用 serverPort 环境变量值 | +| NamespaceID | | nacos 中的 namespace Id, 如果参数为空使用 namespace 环境变量值 | +| ClientDataIDFormat | {{.ClientServiceName}}.{{.ServerServiceName}}.{{.Category}} | 使用 go [template](https://pkg.go.dev/text/template) 语法渲染生成对应的 ID, 使用 `ClientServiceName` `ServiceName` `Category` 三个元数据 | +| ServerDataIDFormat | {{.ServerServiceName}}.{{.Category}} | 使用 go [template](https://pkg.go.dev/text/template) 语法渲染生成对应的 ID, 使用 `ServiceName` `Category` 两个元数据 | +| Group | DEFAULT_GROUP | 使用固定值,也可以动态渲染,用法同 DataIDFormat | ### 治理策略 下面例子中的 configDataId 以及 configGroup 均使用默认值,服务名称为 ServiceName,客户端名称为 ClientName -#### 限流 +#### 限流 + Category=limit + > 限流目前只支持服务端,所以 ClientServiceName 为空。 [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/limiter/item_limiter.go#L33) -|字段|说明| -|----|----| -|connection_limit|最大并发数量| -|qps_limit|每 100ms 内的最大请求数量| +| 字段 | 说明 | +| ---------------- | ------------------------- | +| connection_limit | 最大并发数量 | +| qps_limit | 每 100ms 内的最大请求数量 | 例子: @@ -244,25 +248,27 @@ Category=limit ```json { - "connection_limit": 100, - "qps_limit": 2000 + "connection_limit": 100, + "qps_limit": 2000 } ``` + 注: - 限流配置的粒度是 Server 全局,不分 client、method - 「未配置」或「取值为 0」表示不开启 - connection_limit 和 qps_limit 可以独立配置,例如 connection_limit = 100, qps_limit = 0 -#### 重试 +#### 重试 + Category=retry [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/retry/policy.go#L63) -|参数|说明| -|----|----| -|type| 0: failure_policy 1: backup_policy| -|failure_policy.backoff_policy| 可以设置的策略: `fixed` `none` `random` | +| 参数 | 说明 | +| ----------------------------- | ---------------------------------------- | +| type | 0: failure_policy 1: backup_policy | +| failure_policy.backoff_policy | 可以设置的策略: `fixed` `none` `random` | 例子: @@ -270,46 +276,48 @@ Category=retry ```json { - "*": { - "enable": true, - "type": 0, - "failure_policy": { - "stop_policy": { - "max_retry_times": 3, - "max_duration_ms": 2000, - "cb_policy": { - "error_rate": 0.3 - } - }, - "backoff_policy": { - "backoff_type": "fixed", - "cfg_items": { - "fix_ms": 50 - } - }, - "retry_same_node": false + "*": { + "enable": true, + "type": 0, + "failure_policy": { + "stop_policy": { + "max_retry_times": 3, + "max_duration_ms": 2000, + "cb_policy": { + "error_rate": 0.3 } - }, - "echo": { - "enable": true, - "type": 1, - "backup_policy": { - "retry_delay_ms": 100, - "retry_same_node": false, - "stop_policy": { - "max_retry_times": 2, - "max_duration_ms": 300, - "cb_policy": { - "error_rate": 0.2 - } - } + }, + "backoff_policy": { + "backoff_type": "fixed", + "cfg_items": { + "fix_ms": 50 } + }, + "retry_same_node": false } + }, + "echo": { + "enable": true, + "type": 1, + "backup_policy": { + "retry_delay_ms": 100, + "retry_same_node": false, + "stop_policy": { + "max_retry_times": 2, + "max_duration_ms": 300, + "cb_policy": { + "error_rate": 0.2 + } + } + } + } } ``` -注:retry.Container 内置支持用 * 通配符指定默认配置(详见 [getRetryer](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/retry/retryer.go#L240) 方法) -#### 超时 +注:retry.Container 内置支持用 \* 通配符指定默认配置(详见 [getRetryer](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/retry/retryer.go#L240) 方法) + +#### 超时 + Category=rpc_timeout [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/rpctimeout/item_rpc_timeout.go#L42) @@ -321,7 +329,7 @@ Category=rpc_timeout ```json { "*": { - "conn_timeout_ms": 100, + "conn_timeout_ms": 100, "rpc_timeout_ms": 3000 }, "echo": { @@ -330,16 +338,18 @@ Category=rpc_timeout } } ``` + 注:kitex 的熔断实现目前不支持修改全局默认配置(详见 [initServiceCB](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/circuitbreak/cbsuite.go#L195)) -#### 熔断: +#### 熔断: + Category=circuit_break [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/circuitbreak/item_circuit_breaker.go#L30) -|参数|说明| -|----|----| -|min_sample| 最小的统计样本数| +| 参数 | 说明 | +| ---------- | ---------------- | +| min_sample | 最小的统计样本数 | 例子: @@ -351,17 +361,16 @@ echo 方法使用下面的配置(0.3、100),其他方法使用全局默认 { "echo": { "enable": true, - "err_rate": 0.3, - "min_sample": 100 + "err_rate": 0.3, + "min_sample": 100 } } ``` ## 注意 + 在启动后不要删除 Nacos 上的配置信息,不然会产生大量的警告日志 ## 兼容性 -该包使用 Nacos1.x 客户端,Nacos2.0 和 Nacos1.0 服务端完全兼容该版本. [详情](https://nacos.io/zh-cn/docs/v2/upgrading/2.0.0-compatibility.html) - - +该包使用 Nacos1.x 客户端,Nacos2.0 和 Nacos1.0 服务端完全兼容该版本. [详情](https://nacos.io/zh-cn/docs/v2/upgrading/2.0.0-compatibility.html) diff --git a/content/zh/docs/kitex/Tutorials/service-governance/config-center/zookeeper.md b/content/zh/docs/kitex/Tutorials/service-governance/config-center/zookeeper.md index 840cd717ef..8744fe2ab4 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/config-center/zookeeper.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/config-center/zookeeper.md @@ -2,10 +2,10 @@ title: "Zookeeper" date: 2023-12-18 weight: 5 -keywords: ["配置中心扩展","ZooKeeper"] +keywords: ["配置中心扩展", "ZooKeeper"] description: "使用 ZooKeeper 作为 Kitex 的服务治理配置中心" - --- + ## 安装 `go get github.com/kitex-contrib/config-zookeeper` @@ -234,13 +234,13 @@ type ConfigParam struct { kitex-contrib/config-zookeeper 中的最终 path 由 ConfigParam 中的 Prefix 和 Path 拼接而成:`param.Prefix + "/" + param.Path` -| 参数 | 变量默认值 | 作用 | -| ---------------- | ----------------------------------------------------------- | ------------------------------------------------------------ | -| Servers | 127.0.0.1:2181 | Zookeeper的服务器节点 | -| Prefix | /KitexConfig | Zookeeper中的 prefix | +| 参数 | 变量默认值 | 作用 | +| ---------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | +| Servers | 127.0.0.1:2181 | Zookeeper的服务器节点 | +| Prefix | /KitexConfig | Zookeeper中的 prefix | | ClientPathFormat | {{.ClientServiceName}}/{{.ServerServiceName}}/{{.Category}} | 使用 go [template](https://pkg.go.dev/text/template) 语法渲染生成对应的 ID, 使用 `ClientServiceName` `ServiceName` `Category` 三个元数据 | -| ServerPathFormat | {{.ServerServiceName}}/{{.Category}} | 使用 go [template](https://pkg.go.dev/text/template) 语法渲染生成对应的 ID, 使用 `ServiceName` `Category` 两个元数据 | -| ConfigParser | defaultConfigParser | 解析 json 数据的解析器 | +| ServerPathFormat | {{.ServerServiceName}}/{{.Category}} | 使用 go [template](https://pkg.go.dev/text/template) 语法渲染生成对应的 ID, 使用 `ServiceName` `Category` 两个元数据 | +| ConfigParser | defaultConfigParser | 解析 json 数据的解析器 | ### 治理策略 @@ -270,8 +270,6 @@ Category=limit } ``` - - 注: - 限流配置的粒度是 Server 全局,不分 client、method @@ -295,51 +293,49 @@ Category=retry ```json { - "*": { - "enable": true, - "type": 0, - "failure_policy": { - "stop_policy": { - "max_retry_times": 3, - "max_duration_ms": 2000, - "cb_policy": { - "error_rate": 0.3 - } - }, - "backoff_policy": { - "backoff_type": "fixed", - "cfg_items": { - "fix_ms": 50 - } - }, - "retry_same_node": false + "*": { + "enable": true, + "type": 0, + "failure_policy": { + "stop_policy": { + "max_retry_times": 3, + "max_duration_ms": 2000, + "cb_policy": { + "error_rate": 0.3 } - }, - "echo": { - "enable": true, - "type": 1, - "backup_policy": { - "retry_delay_ms": 100, - "retry_same_node": false, - "stop_policy": { - "max_retry_times": 2, - "max_duration_ms": 300, - "cb_policy": { - "error_rate": 0.2 - } - } + }, + "backoff_policy": { + "backoff_type": "fixed", + "cfg_items": { + "fix_ms": 50 } + }, + "retry_same_node": false } + }, + "echo": { + "enable": true, + "type": 1, + "backup_policy": { + "retry_delay_ms": 100, + "retry_same_node": false, + "stop_policy": { + "max_retry_times": 2, + "max_duration_ms": 300, + "cb_policy": { + "error_rate": 0.2 + } + } + } + } } ``` - - -注:retry.Container 内置支持用 * 通配符指定默认配置(详见 [getRetryer](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/retry/retryer.go#L240) 方法) +注:retry.Container 内置支持用 \* 通配符指定默认配置(详见 [getRetryer](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/retry/retryer.go#L240) 方法) #### 超时 - Category=rpc_timeout +Category=rpc_timeout [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/rpctimeout/item_rpc_timeout.go#L42) @@ -360,13 +356,11 @@ Category=retry } ``` - - 注:kitex 的熔断实现目前不支持修改全局默认配置(详见 [initServiceCB](https://github.com/cloudwego/kitex/blob/v0.5.1/pkg/circuitbreak/cbsuite.go#L195)) #### 熔断 - Category=circuit_break +Category=circuit_break [JSON Schema](https://github.com/cloudwego/kitex/blob/develop/pkg/circuitbreak/item_circuit_breaker.go#L30) @@ -389,4 +383,3 @@ echo 方法使用下面的配置(0.3, 100),其他方法使用全局默认 } } ``` - diff --git a/content/zh/docs/kitex/Tutorials/service-governance/fallback.md b/content/zh/docs/kitex/Tutorials/service-governance/fallback.md index 184613311c..5471840896 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/fallback.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/fallback.md @@ -6,7 +6,7 @@ keywords: ["Kitex", "Fallback", "降级"] description: Kitex 自定义 Fallback 使用指南。 --- -> **支持版本:>= v0.5.0 (go.mod依赖 [github/cloudwego/kitex](https://github.com/cloudwego/kitex))** +> **支持版本:>= v0.5.0 (go.mod依赖 [github/cloudwego/kitex](https://github.com/cloudwego/kitex))** > > Protobuf 生成代码版本:>=v0.5.0(版本见生成代码文件头部与版本注释) > @@ -127,7 +127,7 @@ fallback.NewFallbackPolicy(fallback.UnwrapHelper(func(ctx context.Context, req, 2. **只对 Error(包括业务 Error) 进行 Fallback** - 非 Error 不会执行 Fallback + 非 Error 不会执行 Fallback ```Go // 1: XXXArgs/XXXResult as params @@ -146,7 +146,7 @@ fallback.ErrorFallback(fallback.UnwrapHelper(func(ctx context.Context, req, resp 3. **只对超时和熔断 Error 进行 Fallback** - 非 超时 和 熔断 Error 不会执行 Fallback + 非 超时 和 熔断 Error 不会执行 Fallback ```Go // 1: XXXArgs/XXXResult as params @@ -169,12 +169,11 @@ fallback.TimeoutAndCBFallback(fallback.UnwrapHelper(func(ctx context.Context, re **注意**:如果原结果本来就不是 RPC 失败(业务 Error),但如果在 Fallback 里返回了 error,即使 设置了 EnableReportAsFallback,框架也不会以 Fallback 结果上报。 -| **原结果** | **是否使用 EnableReportAsFallback()** | **上报结果** | -|---------------------------------|----------------------------------|-----------------------------------------------------------------| -| RPC 失败 | 是 | fallback 结果 | -| RPC 失败 | 否 | is_error=1
(rpcinfo.GetRPCInfo(ctx).Stats().Error() is not nil) | -| 业务错误 (Biz Err 或 BaseResp 非成功状态) | 是/否 | is_error=0
(rpcinfo.GetRPCInfo(ctx).Stats().Error() is nil) | - +| **原结果** | **是否使用 EnableReportAsFallback()** | **上报结果** | +| ------------------------------------------- | ------------------------------------- | -------------------------------------------------------------------- | +| RPC 失败 | 是 | fallback 结果 | +| RPC 失败 | 否 | is_error=1
(rpcinfo.GetRPCInfo(ctx).Stats().Error() is not nil) | +| 业务错误 (Biz Err 或 BaseResp 非成功状态) | 是/否 | is_error=0
(rpcinfo.GetRPCInfo(ctx).Stats().Error() is nil) | ### 2.4 配置示例 diff --git a/content/zh/docs/kitex/Tutorials/service-governance/limiting.md b/content/zh/docs/kitex/Tutorials/service-governance/limiting.md index 83f103044c..a11e259e49 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/limiting.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/limiting.md @@ -19,6 +19,7 @@ description: "Kitex 默认限流和自定义限流使用指南。" ## 使用默认的限流器 ### 代码示例 + ```go import "github.com/cloudwego/kitex/pkg/limit" diff --git a/content/zh/docs/kitex/Tutorials/service-governance/loadbalance.md b/content/zh/docs/kitex/Tutorials/service-governance/loadbalance.md index e5bcabf759..da443966f7 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/loadbalance.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/loadbalance.md @@ -68,7 +68,6 @@ cli, err := echo.NewClient("echo", client.WithLoadBalancer(loadbalance.NewWeight cli, err := echo.NewClient("echo", client.WithLoadBalancer(loadbalance.NewWeightedRandomWithAliasMethodBalancer())) ``` - ## ConsistentHash ### 简介 @@ -145,12 +144,12 @@ BenchmarkNewConsistPicker_NoCache/10000ins-16 4 251160920 ns build 和 请求 信息都会被缓存,所以一次正常请求(不需要 build)的时延和节点多少无关,如下: -```` -BenchmarkNewConsistPicker/10ins-16 12557137 81.1 ns/op 0 B/op 0 allocs/op -BenchmarkNewConsistPicker/100ins-16 13704381 82.3 ns/op 0 B/op 0 allocs/op -BenchmarkNewConsistPicker/1000ins-16 14418103 81.3 ns/op 0 B/op 0 allocs/op +``` +BenchmarkNewConsistPicker/10ins-16 12557137 81.1 ns/op 0 B/op 0 allocs/op +BenchmarkNewConsistPicker/100ins-16 13704381 82.3 ns/op 0 B/op 0 allocs/op +BenchmarkNewConsistPicker/1000ins-16 14418103 81.3 ns/op 0 B/op 0 allocs/op BenchmarkNewConsistPicker/10000ins-16 13942186 81.0 ns/op 0 B/op 0 allocs/op -```` +``` ### 注意事项 diff --git a/content/zh/docs/kitex/Tutorials/service-governance/retry.md b/content/zh/docs/kitex/Tutorials/service-governance/retry.md index adc5dd9fc4..55d0aa6094 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/retry.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/retry.md @@ -9,8 +9,9 @@ description: Kitex 异常重试与 Backup Request 策略介绍与使用指南。 ## 重试功能说明 目前有三类重试:异常重试、Backup Request,建连失败重试(默认)。其中建连失败是网络层面问题,由于请求未发出,框架会默认重试。 本文档介绍前两类重试的使用: - - 异常重试:提高服务整体的成功率 - - Backup Request:减少服务的延迟波动 + +- 异常重试:提高服务整体的成功率 +- Backup Request:减少服务的延迟波动 因为很多的业务请求不具有幂等性,这两类重试不会作为默认策略。 @@ -22,29 +23,30 @@ description: Kitex 异常重试与 Backup Request 策略介绍与使用指南。 ## 重试策略 异常重试和 Backup Request 策略方法粒度上只能配置其中之一。 + - 异常重试 默认只对超时重试,可配置支持指定异常或 Resp 重试。 -| 配置项 | 默认值 | 说明 | 限制 | -| ------------------ | ------ | --------------------------------------------------------------------------------------------------------------------------------------- | --------------- | -| `MaxRetryTimes` | 2 | 最大重试次数,不包含首次请求。如果配置为 0 表示停止重试。 | 合法值:[0-5] | -| `MaxDurationMS` | 0 | 累计最大耗时,包括首次失败请求和重试请求耗时,如果耗时达到了限制的时间则停止后续的重试。0 表示无限制。注意:如果配置,该配置项必须大于请求超时时间。 | | -| `EERThreshold` | 10% | 重试熔断错误率阈值, 方法级别请求错误率超过阈值则停止重试。 | 合法值:(0-30%] | -| `ChainStop` | - | 链路中止, 默认启用。如果上游请求是重试请求,不会重试。 | >= v0.0.5 后作为默认策略 | -| `DDLStop` | false | 链路超时中止,该策略是从链路的超时时间判断是否需要重试。注意,Kitex 未内置该实现,需通过 retry.RegisterDDLStop(ddlStopFunc) 注册 DDL func,结合链路超时判断,实现上建议基于上游的发起调用的时间戳和超时时间判断。​​ | | -| `BackOff` | None | 重试等待策略,默认立即重试(`NoneBackOff`)。可选:固定时长退避 (`FixedBackOff`)、随机时长退避 (`RandomBackOff`)。 | | -| `RetrySameNode` | false | 框架默认选择其他节点重试,若需要同节点重试,可配置为 true。 | | +| 配置项 | 默认值 | 说明 | 限制 | +| --------------- | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------ | +| `MaxRetryTimes` | 2 | 最大重试次数,不包含首次请求。如果配置为 0 表示停止重试。 | 合法值:[0-5] | +| `MaxDurationMS` | 0 | 累计最大耗时,包括首次失败请求和重试请求耗时,如果耗时达到了限制的时间则停止后续的重试。0 表示无限制。注意:如果配置,该配置项必须大于请求超时时间。 | | +| `EERThreshold` | 10% | 重试熔断错误率阈值, 方法级别请求错误率超过阈值则停止重试。 | 合法值:(0-30%] | +| `ChainStop` | - | 链路中止, 默认启用。如果上游请求是重试请求,不会重试。 | >= v0.0.5 后作为默认策略 | +| `DDLStop` | false | 链路超时中止,该策略是从链路的超时时间判断是否需要重试。注意,Kitex 未内置该实现,需通过 retry.RegisterDDLStop(ddlStopFunc) 注册 DDL func,结合链路超时判断,实现上建议基于上游的发起调用的时间戳和超时时间判断。​​ | | +| `BackOff` | None | 重试等待策略,默认立即重试(`NoneBackOff`)。可选:固定时长退避 (`FixedBackOff`)、随机时长退避 (`RandomBackOff`)。 | | +| `RetrySameNode` | false | 框架默认选择其他节点重试,若需要同节点重试,可配置为 true。 | | - Backup Request -| 配置项 | 默认值 | 说明 | 限制 | -| ------------------ | ------ | ------------------------------------------------------------------------------------------------------ | --------------- | -| `RetryDelayMS` | - | Backup Request 的等待时间,若该时间内若请求未返回,会发送新的请求。必须手动配置,建议参考 TP99。 | | -| `MaxRetryTimes` | 1 | 最大重试次数,不包含首次请求。 如果配置为 0 表示停止重试。 | 合法值:[0-2] | -| `EERThreshold` | 10% | 重试熔断错误率阈值,方法级别请求错误率超过阈值则停止重试。 | 合法值:(0-30%] | -| `ChainStop` | - | 链路中止, 默认启用。如果上游请求是重试请求,不会发送 Backup Request。 | >= v0.0.5 后作为默认策略 | -| `RetrySameNode` | false | 框架默认选择其他节点重试,若需要同节点重试,可配置为 true | | +| 配置项 | 默认值 | 说明 | 限制 | +| --------------- | ------ | ------------------------------------------------------------------------------------------------ | ------------------------ | +| `RetryDelayMS` | - | Backup Request 的等待时间,若该时间内若请求未返回,会发送新的请求。必须手动配置,建议参考 TP99。 | | +| `MaxRetryTimes` | 1 | 最大重试次数,不包含首次请求。 如果配置为 0 表示停止重试。 | 合法值:[0-2] | +| `EERThreshold` | 10% | 重试熔断错误率阈值,方法级别请求错误率超过阈值则停止重试。 | 合法值:(0-30%] | +| `ChainStop` | - | 链路中止, 默认启用。如果上游请求是重试请求,不会发送 Backup Request。 | >= v0.0.5 后作为默认策略 | +| `RetrySameNode` | false | 框架默认选择其他节点重试,若需要同节点重试,可配置为 true | | ## 使用方式 @@ -124,7 +126,7 @@ type ShouldResultRetry struct { - 关于 Resp: - Thrift 和 KitexProtobuf 协议 Resp 对应的是生成代码中的 *XXXResult,不是真实的业务 Resp,获取真实的 Resp 需要断言 `interface{ GetResult() interface{} }`; + Thrift 和 KitexProtobuf 协议 Resp 对应的是生成代码中的 \*XXXResult,不是真实的业务 Resp,获取真实的 Resp 需要断言 `interface{ GetResult() interface{} }`; - 关于 Error: @@ -183,13 +185,17 @@ respRetry := func(resp interface{}, ri rpcinfo.RPCInfo) bool { - Retry Delay 建议 建议配置为 TP99,则 1% 请求会触发 Backup Request。 + - 配置示例: + ```go // 首次请求 xxx ms未返回,发起 backup 请求,并开启链路中止 bp := retry.NewBackupPolicy(xxx) xxxCli := xxxservice.NewClient(targetService, client.WithBackupRequest(bp)) ``` + - 策略选择: + ```go bp := retry.NewBackupPolicy(xxx) diff --git a/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/_index.md b/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/_index.md index fb787dff99..c663b26feb 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/_index.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/_index.md @@ -3,7 +3,18 @@ title: "服务发现" linkTitle: "服务发现" weight: 1 date: 2023-11-30 -keywords: ["服务注册与发现", "nacos", "consul", "etcd", "eureka", "polaris", "servicecomb", "zookeeper", "DNS"] +keywords: + [ + "服务注册与发现", + "nacos", + "consul", + "etcd", + "eureka", + "polaris", + "servicecomb", + "zookeeper", + "DNS", + ] description: "Kitex 框架提供服务注册与发现的扩展,目前已经支持与业界主流注册中心对接。" --- diff --git a/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/consul.md b/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/consul.md index 643eff3447..306033fd8b 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/consul.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/consul.md @@ -40,12 +40,12 @@ import ( ) func main() { - + r, err := consul.NewConsulRegister("127.0.0.1:8500") if err != nil { log.Fatal(err) } - + server := hello.NewServer(new(HelloImpl), server.WithRegistry(r), server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ ServiceName: "greet.server", })) @@ -275,4 +275,3 @@ func main() { ## 完整示例 完整用法示例详见 [example](https://github.com/kitex-contrib/registry-consul/tree/main/example) 。 - diff --git a/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/etcd.md b/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/etcd.md index a36d8e752d..94e470d006 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/etcd.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/etcd.md @@ -203,11 +203,11 @@ func WithDialTimeoutOpt(dialTimeout time.Duration) Option **默认配置** -| 配置名 | 默认值 | 描述 | -| ----------------------------------------------------- | ---------------- | ---------------------------------------------- | -| `WithMaxAttemptTimes(maxAttemptTimes uint) Option` | 5 | 用于设置最大尝试次数,如果为 0,则表示无限尝试 | -| `WithObserveDelay(observeDelay time.Duration) Option` | 30 * time.Second | 用于设置正常连接条件下检查服务状态的延迟时间 | -| `WithRetryDelay(t time.Duration) Option` | 10 * time.Second | 用于设置断开连接后重试的延迟时间 | +| 配置名 | 默认值 | 描述 | +| ----------------------------------------------------- | ----------------- | ---------------------------------------------- | +| `WithMaxAttemptTimes(maxAttemptTimes uint) Option` | 5 | 用于设置最大尝试次数,如果为 0,则表示无限尝试 | +| `WithObserveDelay(observeDelay time.Duration) Option` | 30 \* time.Second | 用于设置正常连接条件下检查服务状态的延迟时间 | +| `WithRetryDelay(t time.Duration) Option` | 10 \* time.Second | 用于设置断开连接后重试的延迟时间 | ## 服务发现 @@ -272,7 +272,7 @@ import ( etcd "github.com/kitex-contrib/registry-etcd" ) -func main() { +func main() { // creates a etcd based resolver with given username and password r, err := etcd.NewEtcdResolverWithAuth([]string{"127.0.0.1:2379"}, "username", "password") if err != nil { @@ -431,4 +431,3 @@ type instanceInfo struct { ## 完整示例 完整用法示例详见 [example](https://github.com/kitex-contrib/registry-etcd/tree/main/example) 。 - diff --git a/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/eureka.md b/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/eureka.md index 73a72a0991..25ca6e7c9b 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/eureka.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/eureka.md @@ -41,7 +41,7 @@ func main() { ... r = euregistry.NewEurekaRegistry([]string{"http://127.0.0.1:8080/eureka"}, 15*time.Second) svr := echo.NewServer(new(EchoImpl), server.WithRegistry(r), - server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "test"}), + server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "test"}), ) if err := svr.Run(); err != nil { log.Println("server stopped with error:", err) @@ -79,7 +79,7 @@ import ( func main() { ... r = resolver.NewEurekaResolver([]string{"http://127.0.0.1:8080/eureka"}) - client, err := echo.NewClient("echo", + client, err := echo.NewClient("echo", client.WithResolver(r), ) if err != nil { @@ -170,4 +170,3 @@ func main() { ## 完整示例 完整用法示例详见 [example](https://github.com/kitex-contrib/registry-eureka/tree/main/example)。 - diff --git a/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/nacos.md b/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/nacos.md index 45f263f030..fc6e0be86f 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/nacos.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/nacos.md @@ -5,7 +5,7 @@ weight: 5 keywords: ["服务注册与发现", "nacos"] description: "Kitex 提供的服务注册与发现 nacos 拓展。" --- - + ## 安装 - nacos-sdk-go v1 版本 @@ -57,15 +57,15 @@ import ( ) func main() { - // ... + // ... r, err := registry.NewDefaultNacosRegistry() if err != nil { panic(err) } svr := echo.NewServer( - new(EchoImpl), + new(EchoImpl), server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "echo"}), - server.WithRegistry(r), + server.WithRegistry(r), ) if err := svr.Run(); err != nil { log.Println("server stopped with error:", err) @@ -103,7 +103,7 @@ func main() { sc := []constant.ServerConfig{ *constant.NewServerConfig("127.0.0.1", 8848), } - + cc := constant.ClientConfig{ NamespaceId: "public", TimeoutMs: 5000, @@ -114,7 +114,7 @@ func main() { Username: "your-name", Password: "your-password", } - + cli, err := clients.NewNamingClient( vo.NacosClientParam{ ClientConfig: &cc, @@ -124,8 +124,8 @@ func main() { if err != nil { panic(err) } - - svr := echo.NewServer(new(EchoImpl), + + svr := echo.NewServer(new(EchoImpl), server.WithServerBasicInfo(&rpcinfo.EndpointBasicInfo{ServiceName: "echo"}), server.WithRegistry(registry.NewNacosRegistry(cli)), ) @@ -159,7 +159,7 @@ Nacos 扩展提供了 `WithGroup` 用于帮助用户配置自定义的集群。 函数签名: ```go -func WithGroup(group string) Option +func WithGroup(group string) Option ``` ## 服务发现 @@ -198,10 +198,10 @@ import ( ) func main() { - // ... + // ... r, err := resolver.NewDefaultNacosResolver() if err != nil { - panic(err) + panic(err) } client, err := echo.NewClient("echo", client.WithResolver(r)) if err != nil { @@ -234,7 +234,7 @@ import ( // ... ) func main() { - // ... + // ... sc := []constant.ServerConfig{ *constant.NewServerConfig("127.0.0.1", 8848), } @@ -248,7 +248,7 @@ func main() { Username: "your-name", Password: "your-password", } - + cli, err := clients.NewNamingClient( vo.NacosClientParam{ ClientConfig: &cc, @@ -256,7 +256,7 @@ func main() { }, ) if err != nil { - panic(err) + panic(err) } client, err := echo.NewClient("echo", client.WithResolver(resolver.NewNacosResolver(cli)) if err != nil { @@ -287,7 +287,7 @@ Nacos 扩展提供了 `WithGroup` 用于帮助用户配置自定义的集群。 函数签名: ```go -func WithGroup(group string) Option +func WithGroup(group string) Option ``` ## 使用示例 @@ -373,6 +373,7 @@ func main() { } } ``` + ## 注意 - nacos/v2 版本中 kitex 目前不支持多次在同分组下创建多端口示例 diff --git a/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/polaris.md b/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/polaris.md index b6d6144bd7..deb3ddf6a0 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/polaris.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/polaris.md @@ -31,7 +31,7 @@ func NewPolarisRegistry(so ServerOptions, configFile ...string) (Registry, error ```go import ( // ... - + "github.com/cloudwego/kitex-examples/hello/kitex_gen/api" "github.com/cloudwego/kitex-examples/hello/kitex_gen/api/hello" "github.com/cloudwego/kitex/pkg/registry" @@ -87,7 +87,7 @@ func NewPolarisResolver(o ClientOptions, configFile ...string) (Resolver, error) ```go import ( // ... - + "github.com/cloudwego/kitex-examples/hello/kitex_gen/api" "github.com/cloudwego/kitex-examples/hello/kitex_gen/api/hello" "github.com/cloudwego/kitex/client" diff --git a/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/rule-based.md b/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/rule-based.md index 9f6c19e3ad..be0bcead5e 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/rule-based.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/rule-based.md @@ -24,41 +24,42 @@ Kitex 拓展 [resolver-rule-based](https://github.com/kitex-contrib/resolver-rul 2. 定义过滤规则。 - ```go - // 定义一个过滤函数 - // 例如,只获取具有标签 {"k":"v"} 的实例 - filterFunc := func(ctx context.Context, instance []discovery.Instance) []discovery.Instance { - var res []discovery.Instance - for _, ins := range instance { - if v, ok := ins.Tag("k"); ok && v == "v" { - res = append(res, ins) - } - } - return res - } - // 构造过滤规则 - filterRule := &FilterRule{Name: "rule-name", Funcs: []FilterFunc{filterFunc}} - ``` + ```go + // 定义一个过滤函数 + // 例如,只获取具有标签 {"k":"v"} 的实例 + filterFunc := func(ctx context.Context, instance []discovery.Instance) []discovery.Instance { + var res []discovery.Instance + for _, ins := range instance { + if v, ok := ins.Tag("k"); ok && v == "v" { + res = append(res, ins) + } + } + return res + } + // 构造过滤规则 + filterRule := &FilterRule{Name: "rule-name", Funcs: []FilterFunc{filterFunc}} + ``` + 注意:FilterFuncs 将按顺序执行。 3. 配置解析器 - ```go - import ( - ruleBasedResolver "github.com/kitex-contrib/resolver-rule-based" - "github.com/cloudwego/kitex/client" - "github.com/cloudwego/kitex/pkg/discovery" - ) - - // 实现你的解析器 - var newResolver discovery.Resolver - - // 使用 `newResolver` 和 `filterRule` 构造一个 RuleBasedResolver - tagResolver := ruleBasedResolver.NewRuleBasedResolver(resolver, filterRule) - - // 在构建 Kitex 客户端时添加此选项 - opt := client.WithResolver(tagResolver) - ``` + ```go + import ( + ruleBasedResolver "github.com/kitex-contrib/resolver-rule-based" + "github.com/cloudwego/kitex/client" + "github.com/cloudwego/kitex/pkg/discovery" + ) + + // 实现你的解析器 + var newResolver discovery.Resolver + + // 使用 `newResolver` 和 `filterRule` 构造一个 RuleBasedResolver + tagResolver := ruleBasedResolver.NewRuleBasedResolver(resolver, filterRule) + + // 在构建 Kitex 客户端时添加此选项 + opt := client.WithResolver(tagResolver) + ``` ## 示例 diff --git a/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/service-comb.md b/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/service-comb.md index 18c5d4c173..7e7f751658 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/service-comb.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/service-comb.md @@ -345,4 +345,3 @@ func main() { ## 完整示例 完整用法示例详见 [example](https://github.com/kitex-contrib/registry-servicecomb/tree/main/example)。 - diff --git a/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/zookeeper.md b/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/zookeeper.md index b270c30fbc..0033f184bb 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/zookeeper.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/service_discovery/zookeeper.md @@ -171,4 +171,3 @@ func main() { ## 完整示例 完整示例见 [discovery_test.go](https://github.com/kitex-contrib/registry-zookeeper/blob/main/discovery_test.go)。 - diff --git a/content/zh/docs/kitex/Tutorials/service-governance/timeout.md b/content/zh/docs/kitex/Tutorials/service-governance/timeout.md index 6a324269db..e30c0f9435 100644 --- a/content/zh/docs/kitex/Tutorials/service-governance/timeout.md +++ b/content/zh/docs/kitex/Tutorials/service-governance/timeout.md @@ -4,7 +4,6 @@ date: 2023-09-19 weight: 3 keywords: ["Kitex", "超时"] description: "Kitex 中共有几种「超时」:客户端连接超时(Connection Timeout)、客户端请求超时(RPC Timeout)、服务端读写超时(Read/Write Timeout)、服务端退出超时(Exit Wait Timeout)。" - --- ## 使用方式 @@ -16,6 +15,7 @@ description: "Kitex 中共有几种「超时」:客户端连接超时(Connecti ##### 连接超时:ConnTimeout (default=50ms) 说明: + 1. 建立一条新连接的最大等待时间; 2. 可设置为任意值(无上限);如未设置,默认值为 50ms; 3. 如经常遇到 dial timeout 可考虑调大该值,及使用长连接池(详见 client.WithLongConnection)。 @@ -23,6 +23,7 @@ description: "Kitex 中共有几种「超时」:客户端连接超时(Connecti ##### 请求超时:RPCTimeout (default=0, 不限时) 说明: + 1. 限制一次 rpc 调用的最大用时;如超时,返回 `kerrors.ErrRPCTimeout`; 2. 可指定任意值(无上限);如未指定,默认为 0,表示不限制等待时间; 3. 超时默认不会重试。 @@ -32,6 +33,7 @@ description: "Kitex 中共有几种「超时」:客户端连接超时(Connecti ##### 代码配置 - Client Option(Client 粒度配置) 在初始化 client 时传入: + ```go import "github.com/cloudwego/kitex/client" @@ -39,18 +41,21 @@ cli, err := xxx.NewClient(targetService, client.WithConnectTimeout(100 * time.Millisecond), client.WithRPCTimeout(2 * time.Second)) ``` + 注:两个配置项可以按需独立配置。 ##### 代码配置 - Call Option(请求粒度配置,优先级高于 client option) 发起请求时传入: + ```go import "github.com/cloudwego/kitex/client/callopt" -rsp, err := cli.YourMethod(ctx, req, +rsp, err := cli.YourMethod(ctx, req, callopt.WithConnectTimeout(100 * time.Millisecond)) callopt.WithRPCTimeout(2 * time.Second)) ``` + 注:两个配置项可以按需独立配置。 ##### 动态配置 - TimeoutProvider(优先级低于前述 Option) @@ -58,6 +63,7 @@ rsp, err := cli.YourMethod(ctx, req, 适用于需要动态配置的场景,每次请求前,Client 会调用 `TimeoutProvider 获取 RPCTimeout 和 ConnectionTimeout。 在初始化 client 时传入用户自定义的 `rpcinfo.TimeoutProvider`: + ```go import ( "github.com/cloudwego/kitex/client" @@ -78,6 +84,7 @@ cli, err := xxx.NewClient(targetService, opt) ##### 配置中心扩展 可用的配置中心扩展: + - [config-nacos](https://github.com/kitex-contrib/config-nacos): 使用 Nacos 作为配置中心,支持超时、重试、熔断、服务端限流 #### 超时错误 @@ -85,12 +92,14 @@ cli, err := xxx.NewClient(targetService, opt) ##### 请求超时(kerrors.ErrRPCTimeout) 在请求超时的情况下,Client 收到的 Error 为: + ```go &kerrors.DetailedError { basic: kerrors.ErrRPCTimeout, cause: errors.New("timeout=100ms, to=ServerName, method=MethodName, location=kitex.rpcTimeoutMW, remote=0.0.0.0:8888"), } ``` + 可使用 `kerrors.IsTimeoutError(err)` 来判断是否是超时错误。 ##### 错误拆分 @@ -106,6 +115,7 @@ cli, err := xxx.NewClient(targetService, opt) 某些业务场景需要区分这些原因,例如同时发出多个请求,只要有一个请求成功,其他请求就会被 cancel,但这不是 RPC 或业务错误,希望区分这类结果,以免引起报警。 考虑到前向兼容,该配置默认关闭,需要在代码中主动设置: + ```go import "github.com/cloudwego/kitex/pkg/rpctimeout" @@ -114,20 +124,22 @@ rpctimeout.EnableGlobalNeedFineGrainedErrCode() 开启前后区别如下: -| Scenarios | Disabled | Enabled | -| --------- | -------- | ------- | -| kitex 设置的超时到期 | kerrors.ErrRPCTimeout | kerrors.ErrRPCTimeout | -| 业务主动调用 ctx.Cancel() | (同上) | kerrors.ErrCanceledByBusiness | -| 业务代码设置的超时到期(比kitex配置更短的 timeout)| (同上) |kerrors.ErrTimeoutByBusiness (\*注) | +| Scenarios | Disabled | Enabled | +| --------------------------------------------------- | --------------------- | ----------------------------------- | +| kitex 设置的超时到期 | kerrors.ErrRPCTimeout | kerrors.ErrRPCTimeout | +| 业务主动调用 ctx.Cancel() | (同上) | kerrors.ErrCanceledByBusiness | +| 业务代码设置的超时到期(比kitex配置更短的 timeout) | (同上) | kerrors.ErrTimeoutByBusiness (\*注) | \*注:考虑到 go 的 timer 有误差,在超时发生时,会判断 actualDDL + 50ms < Kitex's DDL,满足条件才会返回该错误码,否则仍返回 103。 例如 Kitex 设置 1s 超时: + - 如果实际 <950ms 就超时返回,说明大概率是业务代码里设置了 timer - 如果实际 >= 1s 才超时返回,说明大概率是 Kitex 设置的 timer - 如果在 950ms ~ 1s 之间超时,由于无法精确判断,目前保守地判定为 Kitex 设置的 timer 该阈值 (50ms) 在 Kitex >= 0.7.1 可通过如下方式修改: + ```go rpctimeout.SetBusinessTimeoutThreshold(10 * time.Millisecond) ``` @@ -139,6 +151,7 @@ rpctimeout.SetBusinessTimeoutThreshold(10 * time.Millisecond) ##### ReadWriteTimeout (default=5s) 说明: + 1. 在连接上读写数据所能忍受的最大等待时间,主要为防止异常连接卡住协程; 2. 不是 Handler 执行超时时间; 3. 只在 server 端生效,一般无需关心。 @@ -148,6 +161,7 @@ rpctimeout.SetBusinessTimeoutThreshold(10 * time.Millisecond) ##### ExitWaitTime(default=5s) 说明: + 1. Server 在收到退出信号时的等待时间; 2. 如果超过该等待时间,Server 将会强制结束所有在处理的请求(客户端会收到错误)。 @@ -160,6 +174,7 @@ rpctimeout.SetBusinessTimeoutThreshold(10 * time.Millisecond) 具体用法请参考后文示例代码。 说明: + - Streaming API:已默认开启(通过另外的实现) - 含 GRPC/Protobuf 和 Thrift Streaming - client 的 `ctx.Deadline()` 会通过 `grpc_timeout` header 发送给 server,写入 server 的 ctx @@ -168,7 +183,6 @@ rpctimeout.SetBusinessTimeoutThreshold(10 * time.Millisecond) - 在 server 端需启用此 Option 及 ServerTTHeaderMetaHandler,才能从请求的 TTHeader 中读取到 RPCTimeout - 如果业务代码有需要,可用 `rpcinfo.GetRPCInfo(ctx).Config().RPCTimeout()` 获得这个值 - #### 配置方式 ##### 代码配置 - Server Option @@ -176,6 +190,7 @@ rpctimeout.SetBusinessTimeoutThreshold(10 * time.Millisecond) ###### WithReadWriteTimeout 在初始化 Server 时指定: + ```go import "github.com/cloudwego/kitex/server" @@ -187,6 +202,7 @@ svr := yourservice.NewServer(handler, ###### WithExitWaitTime 在初始化 Server 时指定: + ```go import "github.com/cloudwego/kitex/server" @@ -200,12 +216,14 @@ svr := yourservice.NewServer(handler, 该 Option 需配合 TTHeader 使用,详见下方示例代码。 Client + - 指定 Transport Protocol 为 TTHeader - 启用 [transmeta.ClientTTHeaderHandler](https://github.com/cloudwego/kitex/blob/v0.9.0/pkg/transmeta/ttheader.go#L45) - 通过 client.WithRPCTimeout (或者在请求时使用 callopt.WithRPCTimeout)指定超时 + ```go cli := yourservice.MustNewClient( - serverName, + serverName, client.WithTransportProtocol(transport.TTHeader), client.WithMetaHandler(transmeta.ClientTTHeaderHandler), client.WithRPCTimeout(time.Second), @@ -213,8 +231,10 @@ cli := yourservice.MustNewClient( ``` Server + - 指定该 Option - 启用 [transmeta.ServerTTHeaderHandler](https://github.com/cloudwego/kitex/blob/v0.9.0/pkg/transmeta/ttheader.go#L46) + ``` svr := yourservice.NewServer(handler, server.WithMetaHandler(transmeta.ServerTTHeaderHandler), @@ -230,4 +250,4 @@ svr := yourservice.NewServer(handler, ### Q: 服务端支持 handler 执行超时配置吗? -目前服务端不支持 handler 执行超时,只支持读写超时。 \ No newline at end of file +目前服务端不支持 handler 执行超时,只支持读写超时。 diff --git a/content/zh/docs/kitex/_index.md b/content/zh/docs/kitex/_index.md index 70284b9f1f..bc23dc626e 100644 --- a/content/zh/docs/kitex/_index.md +++ b/content/zh/docs/kitex/_index.md @@ -1,10 +1,10 @@ --- -title: 'Kitex' -linkTitle: 'Kitex' +title: "Kitex" +linkTitle: "Kitex" weight: 1 Description: Kitex [kaɪt'eks] 字节跳动内部的 Golang 微服务 RPC 框架,具有**高性能**、**强可扩展**的特点,在字节内部已广泛使用。如果对微服务性能有要求,又希望定制扩展融入自己的治理体系,Kitex 会是一个不错的选择。 menu: main: weight: 1 - parent: '文档' + parent: "文档" --- diff --git a/content/zh/docs/netpoll/Common Usage/_index.md b/content/zh/docs/netpoll/Common Usage/_index.md index 7f381e75e3..d90bde0e62 100644 --- a/content/zh/docs/netpoll/Common Usage/_index.md +++ b/content/zh/docs/netpoll/Common Usage/_index.md @@ -31,9 +31,9 @@ func init() { 现在支持以下策略: 1. Random - * 新连接将分配给随机选择的轮询器。 + - 新连接将分配给随机选择的轮询器。 2. RoundRobin - * 新连接将按顺序分配给轮询器。 + - 新连接将按顺序分配给轮询器。 Netpoll 默认使用 `RoundRobin`,用户可以通过以下方式更改: @@ -130,8 +130,8 @@ func prepare(connection netpoll.Connection) (ctx context.Context) { Netpoll 现在支持两种类型的超时配置: 1. 读超时(`ReadTimeout`) - * 为了保持与 `net.Conn` 相同的操作风格,`Connection.Reader` 也被设计为阻塞读取。 所以提供了读取超时(`ReadTimeout`)。 - * 读超时(`ReadTimeout`)没有默认值(默认无限等待),可以通过 `Connection` 或 `EventLoop.Option` 进行配置,例如: + - 为了保持与 `net.Conn` 相同的操作风格,`Connection.Reader` 也被设计为阻塞读取。 所以提供了读取超时(`ReadTimeout`)。 + - 读超时(`ReadTimeout`)没有默认值(默认无限等待),可以通过 `Connection` 或 `EventLoop.Option` 进行配置,例如: ```go package main @@ -155,8 +155,8 @@ func main() { ``` 2. 空闲超时(`IdleTimeout`) - * 空闲超时(`IdleTimeout`)利用 `TCP KeepAlive` 机制来踢出死连接并减少维护开销。使用 Netpoll 时,一般不需要频繁创建和关闭连接,所以通常来说,空闲连接影响不大。当连接长时间处于非活动状态时,为了防止出现假死、对端挂起、异常断开等造成的死连接,在空闲超时(`IdleTimeout`)后,netpoll 会主动关闭连接。 - * 空闲超时(`IdleTimeout`)的默认配置为 `10min`,可以通过 `Connection` API 或 `EventLoop.Option` 进行配置,例如: + - 空闲超时(`IdleTimeout`)利用 `TCP KeepAlive` 机制来踢出死连接并减少维护开销。使用 Netpoll 时,一般不需要频繁创建和关闭连接,所以通常来说,空闲连接影响不大。当连接长时间处于非活动状态时,为了防止出现假死、对端挂起、异常断开等造成的死连接,在空闲超时(`IdleTimeout`)后,netpoll 会主动关闭连接。 + - 空闲超时(`IdleTimeout`)的默认配置为 `10min`,可以通过 `Connection` API 或 `EventLoop.Option` 进行配置,例如: ```go package main @@ -236,4 +236,3 @@ func callback(connection netpoll.Connection) error { return nil } ``` - diff --git a/content/zh/docs/netpoll/Getting started/_index.md b/content/zh/docs/netpoll/Getting started/_index.md index 32eab8dc22..35143337fa 100644 --- a/content/zh/docs/netpoll/Getting started/_index.md +++ b/content/zh/docs/netpoll/Getting started/_index.md @@ -52,8 +52,8 @@ func main() { 参数说明: -* `OnRequest` 和 `OnConnect` 是用户应该自己实现来处理业务逻辑的接口。 [注释][eventloop.go] 详细描述了它的行为。 -* `Option` 用于自定义 `EventLoop` 创建时的配置,下面的例子展示了它的用法。更多详情请参考 [options][netpoll_options.go] 。 +- `OnRequest` 和 `OnConnect` 是用户应该自己实现来处理业务逻辑的接口。 [注释][eventloop.go] 详细描述了它的行为。 +- `Option` 用于自定义 `EventLoop` 创建时的配置,下面的例子展示了它的用法。更多详情请参考 [options][netpoll_options.go] 。 创建过程如下: @@ -292,19 +292,11 @@ func main() { ``` [Netpoll]: https://github.com/cloudwego/netpoll - [net]: https://github.com/golang/go/tree/master/src/net - [gopool]: https://github.com/bytedance/gopkg/tree/develop/util/gopool - [Examples]: https://github.com/cloudwego/netpoll-examples - [server-example]: https://github.com/cloudwego/netpoll-examples/blob/main/echo/server.go - [client-example]: https://github.com/cloudwego/netpoll-examples/blob/main/echo/client.go - [netpoll_options.go]: https://github.com/cloudwego/netpoll/blob/main/netpoll_options.go - [nocopy.go]: https://github.com/cloudwego/netpoll/blob/main/nocopy.go - -[eventloop.go]: https://github.com/cloudwego/netpoll/blob/main/eventloop.go \ No newline at end of file +[eventloop.go]: https://github.com/cloudwego/netpoll/blob/main/eventloop.go diff --git a/content/zh/docs/netpoll/Overview/_index.md b/content/zh/docs/netpoll/Overview/_index.md index 7cb90ce057..b0df478671 100644 --- a/content/zh/docs/netpoll/Overview/_index.md +++ b/content/zh/docs/netpoll/Overview/_index.md @@ -3,7 +3,6 @@ title: "概览" linkTitle: "概览" weight: 1 description: > - --- ## 简介 @@ -26,23 +25,25 @@ goroutine,大幅增加调度开销。此外,[net.Conn][net.Conn] 没有提 ## 特性 -* **已经支持** - - [LinkBuffer][LinkBuffer] 提供可以流式读写的 nocopy API - - [gopool][gopool] 提供高性能的 goroutine 池 - - [mcache][mcache] 提供高效的内存复用 - - `IsActive` 支持检查连接是否存活 - - `Dialer` 支持构建 client - - `EventLoop` 支持构建 server - - 支持 TCP,Unix Domain Socket - - 支持 Linux,macOS(操作系统) +- **已经支持** + + - [LinkBuffer][LinkBuffer] 提供可以流式读写的 nocopy API + - [gopool][gopool] 提供高性能的 goroutine 池 + - [mcache][mcache] 提供高效的内存复用 + - `IsActive` 支持检查连接是否存活 + - `Dialer` 支持构建 client + - `EventLoop` 支持构建 server + - 支持 TCP,Unix Domain Socket + - 支持 Linux,macOS(操作系统) + +- **即将开源** -* **即将开源** - - Shared Memory IPC - - 支持 TLS - - 支持 UDP + - Shared Memory IPC + - 支持 TLS + - 支持 UDP -* **不被支持** - - Windows(操作系统) +- **不被支持** + - Windows(操作系统) ## 性能 @@ -54,8 +55,8 @@ goroutine,大幅增加调度开销。此外,[net.Conn][net.Conn] 没有提 ## 参考 -* [官方网站](/zh/) -* [使用文档](/zh/docs/netpoll/getting-started/) +- [官方网站](/zh/) +- [使用文档](/zh/docs/netpoll/getting-started/) [Netpoll]: https://github.com/cloudwego/netpoll [net]: https://github.com/golang/go/tree/master/src/net @@ -66,15 +67,12 @@ goroutine,大幅增加调度开销。此外,[net.Conn][net.Conn] 没有提 [Kitex]: https://github.com/cloudwego/kitex [Hertz]: https://github.com/cloudwego/hertz [netpoll-example]: https://github.com/cloudwego/netpoll-examples - [netpoll-benchmark]: https://github.com/cloudwego/netpoll-benchmark [kitex-benchmark]: https://github.com/cloudwego/kitex-benchmark [hertz-benchmark]: https://github.com/cloudwego/hertz-benchmark - [ByteDance]: https://www.bytedance.com [Redis]: https://redis.io [HAProxy]: http://www.haproxy.org - [LinkBuffer]: https://github.com/cloudwego/netpoll/blob/develop/nocopy_linkbuffer.go [gopool]: https://github.com/bytedance/gopkg/tree/develop/util/gopool [mcache]: https://github.com/bytedance/gopkg/tree/develop/lang/mcache diff --git a/content/zh/docs/netpoll/_index.md b/content/zh/docs/netpoll/_index.md index aa6a978d00..05fa3ba681 100644 --- a/content/zh/docs/netpoll/_index.md +++ b/content/zh/docs/netpoll/_index.md @@ -1,10 +1,10 @@ --- -title: 'Netpoll' -linkTitle: 'Netpoll' +title: "Netpoll" +linkTitle: "Netpoll" weight: 4 Description: Netpoll 是由字节跳动开发的高性能 NIO(Non-blocking I/O) 网络库,专注于 RPC 场景。 menu: main: weight: 4 - parent: '文档' + parent: "文档" --- diff --git a/content/zh/docs/volo/_index.md b/content/zh/docs/volo/_index.md index 542dac8778..b5dda26c21 100644 --- a/content/zh/docs/volo/_index.md +++ b/content/zh/docs/volo/_index.md @@ -1,10 +1,10 @@ --- -title: 'Volo' -linkTitle: 'Volo' +title: "Volo" +linkTitle: "Volo" weight: 3 Description: Volo 是字节跳动服务框架团队研发的轻量级、高性能、可扩展性强、易用性好的 Rust RPC 框架,使用了 Rust 最新的 AFIT 和 RPITIT 特性。 menu: main: weight: 3 - parent: '文档' + parent: "文档" --- diff --git a/content/zh/docs/volo/faq/_index.md b/content/zh/docs/volo/faq/_index.md index 4e779eab89..102bf77b12 100644 --- a/content/zh/docs/volo/faq/_index.md +++ b/content/zh/docs/volo/faq/_index.md @@ -4,7 +4,6 @@ linkTitle: "FAQ" weight: 8 keywords: ["Volo", "FAQ", "volo-cli", "poll_ready"] description: 常见问题回答汇总。 - --- ### 为什么 Client 端中间件使用 Arc? @@ -33,6 +32,7 @@ Volo 与 Kitex 完全兼容,包括元信息传递等功能。 这是一个非常精妙的设计,Tower 在 [inventing-the-service-trait](https://tokio.rs/blog/2021-05-14-inventing-the-service-trait) 这篇介绍文章中,也有详细介绍这么设计的原因。 但是在我们真实的开发体验中,我们总结出了以下的经验: + 1. 绝大多数的 `poll_ready` 的实现都是直接 `self.inner.poll_ready(cx)`;剩下的 poll_ready 实现更干脆,直接 `Poll::Ready(Ok(()))`。 2. `poll_ready` 一般不会真正跨服务去 check 负载(也就是说,不会真的发个请求问下游“大兄弟,你还能支棱起来不?”),所以一般也就是在本地的中间件(比如 Tower 的例子是速率限制中间件)里面根据某些特定条件判断一下。 3. 基于上两条,几乎所有的 `poll_ready` 场景,我们都可以直接在 `call` 里面做达到一样的效果,因为实践中外层的 `service` 在返回 `Poll::Pending` 的时候就是空等,不如直接采用 `async-await` 的方式来编写代码,更符合人体工程学。 diff --git a/content/zh/docs/volo/guide/config.md b/content/zh/docs/volo/guide/config.md index 09f1c4117a..e2f2c09ba6 100644 --- a/content/zh/docs/volo/guide/config.md +++ b/content/zh/docs/volo/guide/config.md @@ -3,7 +3,6 @@ title: "volo.yml 配置文件格式" linkTitle: "volo.yml 配置文件格式" weight: 5 description: > - --- ## 功能 @@ -107,16 +106,16 @@ entries: 1. ```bash $ volo init --help init your thrift or grpc project - + Usage: volo init [OPTIONS] - + Arguments: The name of project Specify the path for idl. If -g or --git is specified, then this should be the path in the specified git repo. Example: -g not specified: ./idl/server.thrift -g specified: /path/to/idl/server.thrift - + Options: --repo Specify the git repo name for repo. Example: cloudwego_volo @@ -132,20 +131,20 @@ entries: -V, --version Print version ``` - 2. 在项目根目录下使用 volo init 命令,会自动创建 server 代码模版和生成代码 + 2. 在项目根目录下使用 volo init 命令,会自动创建 server 代码模版和生成代码 2. idl 1. ```bash $ volo idl --help manage your idl - + Usage: volo idl [OPTIONS] - + Commands: add help Print this message or the help of the given subcommand(s) - + Options: -v, --verbose... Turn on the verbose mode. -n, --entry-name The entry name, defaults to 'default'. [default: default] @@ -158,13 +157,13 @@ entries: 1. ```bash $ volo idl add --help Usage: volo idl add [OPTIONS] - + Arguments: Specify the path for idl. If -g or --git is specified, then this should be the path in the specified git repo. Example: -g not specified: ./idl/client.thrift -g specified: /path/to/idl/client.thrift - + Options: --repo Specify the git repo name for repo. Example: cloudwego_volo @@ -189,14 +188,14 @@ entries: 1. ```bash $ volo repo --help manage your repo - + Usage: volo repo [OPTIONS] - + Commands: update update your repo by repo name, split by ',' add help Print this message or the help of the given subcommand(s) - + Options: -v, --verbose... Turn on the verbose mode. -n, --entry-name The entry name, defaults to 'default'. [default: default] @@ -209,7 +208,7 @@ entries: 1. ```bash $ volo repo add --help Usage: volo repo add [OPTIONS] --git - + Options: --repo Specify the git repo name for repo. Example: cloudwego_volo @@ -229,12 +228,12 @@ entries: 1. ```bash $ volo repo update --help update your repo by repo name, split by ',' - + Usage: volo repo update [OPTIONS] [REPOS]... - + Arguments: [REPOS]... - + Options: -v, --verbose... Turn on the verbose mode. -n, --entry-name The entry name, defaults to 'default'. [default: default] diff --git a/content/zh/docs/volo/guide/discovery_lb.md b/content/zh/docs/volo/guide/discovery_lb.md index 3787c6db8d..b25b3b5ae8 100644 --- a/content/zh/docs/volo/guide/discovery_lb.md +++ b/content/zh/docs/volo/guide/discovery_lb.md @@ -3,10 +3,10 @@ title: "自定义服务发现与负载均衡" linkTitle: "自定义服务发现与负载均衡" weight: 2 description: > - --- ## 服务发现 + `Discover` trait 提供了自定义服务发现的能力,其支持自定义静态或可订阅的服务发现能力。 **Trait** 定义 diff --git a/content/zh/docs/volo/guide/metadata.md b/content/zh/docs/volo/guide/metadata.md index 4c20c9b56a..2448483f99 100644 --- a/content/zh/docs/volo/guide/metadata.md +++ b/content/zh/docs/volo/guide/metadata.md @@ -3,7 +3,6 @@ title: "元信息传递" linkTitle: "元信息传递" weight: 4 description: > - --- ## 前言 diff --git a/content/zh/docs/volo/guide/observability.md b/content/zh/docs/volo/guide/observability.md index 15424706ff..8205e26309 100644 --- a/content/zh/docs/volo/guide/observability.md +++ b/content/zh/docs/volo/guide/observability.md @@ -3,7 +3,6 @@ title: "自定义日志/监控打点/trace" linkTitle: "日志/监控打点/trace" weight: 3 description: > - --- 对于 RPC 框架来说,日志、监控和 trace 是很重要的组成部分,云原生环境下可观测性基本依赖这三件套。 diff --git a/content/zh/docs/volo/guide/with_callopt.md b/content/zh/docs/volo/guide/with_callopt.md index 6f1ed55905..b9d277257b 100644 --- a/content/zh/docs/volo/guide/with_callopt.md +++ b/content/zh/docs/volo/guide/with_callopt.md @@ -3,7 +3,6 @@ title: "在调用时指定 CallOpt" linkTitle: "在调用时指定 CallOpt" weight: 1 description: > - --- 为了增加框架的灵活性和易用性,Volo 允许用户在 Client 端使用 `CallOpt` 针对单个请求设置一些请求的元信息。 diff --git a/content/zh/docs/volo/motore/_index.md b/content/zh/docs/volo/motore/_index.md index 9b1177d35c..4af75cd534 100644 --- a/content/zh/docs/volo/motore/_index.md +++ b/content/zh/docs/volo/motore/_index.md @@ -1,8 +1,8 @@ --- -title: 'Motore' -linkTitle: 'Motore' +title: "Motore" +linkTitle: "Motore" weight: 6 -keywords: [ "Motore", "AFIT", "RPITIT"] +keywords: ["Motore", "AFIT", "RPITIT"] Description: Motore 是一个使用了 AFIT 和 RPITIT 特性的中间件抽象层。 --- diff --git a/content/zh/docs/volo/overview/_index.md b/content/zh/docs/volo/overview/_index.md index 05697a97c5..d2299b5e50 100644 --- a/content/zh/docs/volo/overview/_index.md +++ b/content/zh/docs/volo/overview/_index.md @@ -4,7 +4,6 @@ linkTitle: "概览" weight: 1 keywords: ["RPC", "Rust", "Volo", "AFIT", "RPITIT"] description: "Volo 架构设计、框架特性、相关生态简介。" - --- ## Volo @@ -54,6 +53,7 @@ Rust 以~~难学难用~~而闻名,我们希望尽可能降低用户使用 Volo 相关的扩展,我们会放在 [volo-rs](http://github.com/volo-rs) 组织下,也欢迎大家贡献自己的扩展到 volo-rs~ ## 相关生态 + 1. [Volo-rs](http://github.com/volo-rs):Volo 的相关生态 2. [Pilota](https://github.com/cloudwego/pilota):Volo 使用的 Thrift 与 Protobuf 编译器及编解码的纯 Rust 实现(不依赖 protoc) 3. [Motore](https://github.com/cloudwego/motore):Volo 参考 Tower 设计的,使用了 AFIT 和 RPITIT 的 middleware 抽象层 diff --git a/content/zh/docs/volo/pilota/_index.md b/content/zh/docs/volo/pilota/_index.md index 71146a04dd..9f4bbf2d6c 100644 --- a/content/zh/docs/volo/pilota/_index.md +++ b/content/zh/docs/volo/pilota/_index.md @@ -1,8 +1,8 @@ --- -title: 'Pilota' -linkTitle: 'Pilota' +title: "Pilota" +linkTitle: "Pilota" weight: 7 -keywords: [ "Pilota", "Thrift", "Protobuf", "Plugin"] +keywords: ["Pilota", "Thrift", "Protobuf", "Plugin"] Description: Pilota 是一个使用纯 Rust 编写的 Thrift 和 Protobuf 实现,具有高性能和高扩展性。 --- @@ -53,6 +53,7 @@ service TestService { ``` ## 如何编写 Plugin + ### 为什么需要 Plugin 为 Pilota 根据 IDL 生成的 `Struct` 等类型增加一些自定义的 meta 信息。 diff --git a/content/zh/docs/volo/volo-grpc/_index.md b/content/zh/docs/volo/volo-grpc/_index.md index 7a7f3173bc..fabc638c0a 100644 --- a/content/zh/docs/volo/volo-grpc/_index.md +++ b/content/zh/docs/volo/volo-grpc/_index.md @@ -4,6 +4,4 @@ linkTitle: "Volo-gRPC" weight: 3 keywords: ["Volo", "gRPC", "快速上手", "基础教程"] description: "Volo-gRPC 命令行工具安装、快速上手与基础教程。" - --- - diff --git a/content/zh/docs/volo/volo-thrift/_index.md b/content/zh/docs/volo/volo-thrift/_index.md index 7d17a16e19..8374c8c47e 100644 --- a/content/zh/docs/volo/volo-thrift/_index.md +++ b/content/zh/docs/volo/volo-thrift/_index.md @@ -4,5 +4,4 @@ linkTitle: "Volo-Thrift" weight: 2 keywords: ["Volo", "Thrift", "快速上手", "基础教程"] description: "Volo-Thrift 命令行工具安装、快速上手与基础教程。" - --- diff --git a/content/zh/search.md b/content/zh/search.md index e3690fd5a8..394feea5fd 100644 --- a/content/zh/search.md +++ b/content/zh/search.md @@ -1,6 +1,4 @@ --- title: Search Results layout: search - --- - diff --git a/content/zh/security/_index.md b/content/zh/security/_index.md index 03e67a1a2c..af09755b94 100644 --- a/content/zh/security/_index.md +++ b/content/zh/security/_index.md @@ -7,8 +7,6 @@ menu: weight: 50 --- - This is the **security** section. It has two categories: vulnerability-reporting and safety-bulletin. Files in these directories will be listed in reverse chronological order. - diff --git a/content/zh/security/safety-bulletin/detail/_index.md b/content/zh/security/safety-bulletin/detail/_index.md index 94c1b317c0..61cfa0722a 100644 --- a/content/zh/security/safety-bulletin/detail/_index.md +++ b/content/zh/security/safety-bulletin/detail/_index.md @@ -3,4 +3,3 @@ title: "公告详情" linkTitle: "公告详情" weight: 1 --- - diff --git a/content/zh/security/safety-bulletin/detail/cloudwego-sa-2022-1/index.md b/content/zh/security/safety-bulletin/detail/cloudwego-sa-2022-1/index.md index 002dd4af70..b012f61184 100644 --- a/content/zh/security/safety-bulletin/detail/cloudwego-sa-2022-1/index.md +++ b/content/zh/security/safety-bulletin/detail/cloudwego-sa-2022-1/index.md @@ -6,9 +6,11 @@ description: "Connection Leaking" --- ## 简介 + 修复客户端编码失败时连接会泄漏的问题 ## 严重级别 + Low ## 描述 @@ -16,13 +18,17 @@ Low 修复客户端编码失败时连接会泄漏的问题 ## 解决办法 + 当客户端编码失败时,释放连接 ## 影响组件 + kitex-v0.1.3 ## CVE + 无 ## 参考链接 + - https://github.com/cloudwego/kitex/pull/315 diff --git a/content/zh/security/safety-bulletin/detail/cloudwego-sa-2022-2/index.md b/content/zh/security/safety-bulletin/detail/cloudwego-sa-2022-2/index.md index 16f7e122de..bce23e40ed 100644 --- a/content/zh/security/safety-bulletin/detail/cloudwego-sa-2022-2/index.md +++ b/content/zh/security/safety-bulletin/detail/cloudwego-sa-2022-2/index.md @@ -6,12 +6,15 @@ description: Netpoll Panic --- ## 简介 + 修复当“对端关闭 & 本端 user Close” 同时发生时出现 Panic 的问题 ## 严重级别 + Middle ## 描述 + 修复极端场景下的并发问题: 场景:“对端关闭 & 本端 user Close” 同时发生,并且 c.onClose 执行的是 lock(User),同时 poller 也执行到了 p.detaches (三个条件同时满足) @@ -21,16 +24,20 @@ Middle 当程序比较闲时,有可能 c.onClose 已经执行完 close callback 了,freeop 并且已经被复用,又变成 inuse 状态;而这时候 p.detaches 里的 op.unused 才开始执行;这样就会把一个新连接的 operator 错误的置成 0 ,导致后续的 op.do 全失败,变成死循环。 ## 解决办法 + poller 不再异步执行 detach,以保证不会和 c.onClose 并发,改动是性能无损的。 ## 影响组件 + netpoll-v0.2.2 kitex-v0.3.0 ## CVE + 无 ## 参考链接 + - https://github.com/cloudwego/netpoll/issues/149 - https://github.com/cloudwego/netpoll/pull/142